diff --git a/package-lock.json b/package-lock.json
index 7c6d1c7..083ff1f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1307,6 +1307,11 @@
"integrity": "sha512-T7VNNlYVM1SgQ+VsMYhnDkcGmWhQdL0bDyGm5TlQ3GBXnJscEClUUOKduWTmm2zCnvNLC1hc3JpuXjs/nFOc5w==",
"dev": true
},
+ "@techstark/opencv-js": {
+ "version": "4.12.0-release.1",
+ "resolved": "https://registry.npmmirror.com/@techstark/opencv-js/-/opencv-js-4.12.0-release.1.tgz",
+ "integrity": "sha512-LtTaph9v/HqLPXEg3m1xs2h7QJh10pUpuDT0nj8g77lelWnTwwQrehtd+fXElLOdrkqc4Fea6Z/sJBvEJLYPfw=="
+ },
"@types/anymatch": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/@types/anymatch/-/anymatch-1.3.1.tgz",
@@ -4757,8 +4762,7 @@
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
- "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
- "dev": true
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"cosmiconfig": {
"version": "5.2.1",
@@ -7592,6 +7596,11 @@
"dev": true,
"optional": true
},
+ "immediate": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmmirror.com/immediate/-/immediate-3.0.6.tgz",
+ "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="
+ },
"import-cwd": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz",
@@ -8177,8 +8186,7 @@
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
- "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
- "dev": true
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"isexe": {
"version": "2.0.0",
@@ -8373,6 +8381,17 @@
"verror": "1.10.0"
}
},
+ "jszip": {
+ "version": "3.10.1",
+ "resolved": "https://registry.npmmirror.com/jszip/-/jszip-3.10.1.tgz",
+ "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==",
+ "requires": {
+ "lie": "~3.3.0",
+ "pako": "~1.0.2",
+ "readable-stream": "~2.3.6",
+ "setimmediate": "^1.0.5"
+ }
+ },
"keycode": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/keycode/-/keycode-2.2.0.tgz",
@@ -8662,6 +8681,14 @@
"type-check": "~0.3.2"
}
},
+ "lie": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmmirror.com/lie/-/lie-3.3.0.tgz",
+ "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
+ "requires": {
+ "immediate": "~3.0.5"
+ }
+ },
"lines-and-columns": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz",
@@ -10075,8 +10102,7 @@
"pako": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
- "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
- "dev": true
+ "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
},
"parallel-transform": {
"version": "1.2.0",
@@ -10967,8 +10993,7 @@
"process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
- "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
- "dev": true
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
},
"progress": {
"version": "2.0.3",
@@ -11262,7 +11287,6 @@
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
- "dev": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
@@ -11665,8 +11689,7 @@
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
- "dev": true
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"safe-json-parse": {
"version": "4.0.0",
@@ -12028,8 +12051,7 @@
"setimmediate": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
- "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=",
- "dev": true
+ "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU="
},
"setprototypeof": {
"version": "1.1.1",
@@ -12648,7 +12670,6 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
- "dev": true,
"requires": {
"safe-buffer": "~5.1.0"
}
@@ -13459,8 +13480,7 @@
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
- "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
- "dev": true
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"util.promisify": {
"version": "1.0.1",
diff --git a/package.json b/package.json
index 7925835..d28cb4a 100644
--- a/package.json
+++ b/package.json
@@ -9,6 +9,7 @@
"start": "node antdTheme.js && npm run serve"
},
"dependencies": {
+ "@techstark/opencv-js": "^4.12.0-release.1",
"ant-design-vue": "^1.6.3",
"antd-theme-generator": "^1.2.8",
"axios": "^0.19.2",
@@ -18,6 +19,7 @@
"echarts": "^5.4.3",
"echarts-gl": "^2.0.9",
"element-ui": "^2.15.6",
+ "jszip": "^3.10.1",
"path-to-regexp": "^6.2.0",
"style-loader": "^2.0.0",
"v-viewer": "^1.5.1",
diff --git a/public/static/video.js b/public/static/video.js
deleted file mode 100644
index 593aaec..0000000
--- a/public/static/video.js
+++ /dev/null
@@ -1,25674 +0,0 @@
-/**
- * @license
- * Video.js 6.6.2
- * Copyright Brightcove, Inc.
- * Available under Apache License Version 2.0
- *
- *
- * Includes vtt.js
- * Available under Apache License Version 2.0
- *
- */
-
-(function (global, factory) {
- typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
- typeof define === 'function' && define.amd ? define(factory) :
- (global.videojs = factory());
-}(this, (function () {
-
- var version = "6.6.2";
-
- var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
-
-
-
-
-
- function createCommonjsModule(fn, module) {
- return module = { exports: {} }, fn(module, module.exports), module.exports;
- }
-
- var win;
-
- 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;
-
- var empty = {};
-
-
- var empty$1 = (Object.freeze || Object)({
- 'default': empty
- });
-
- var minDoc = ( empty$1 && empty ) || empty$1;
-
- var topLevel = typeof commonjsGlobal !== 'undefined' ? commonjsGlobal :
- typeof window !== 'undefined' ? window : {};
-
-
- var doccy;
-
- if (typeof document !== 'undefined') {
- doccy = document;
- } else {
- doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'];
-
- if (!doccy) {
- doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'] = minDoc;
- }
- }
-
- var document_1 = doccy;
-
- /**
- * @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 {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;
-
- var IOS_VERSION = function () {
- var match = USER_AGENT.match(/OS (\d+)_/i);
-
- if (match && match[1]) {
- return match[1];
- }
- return null;
- }();
-
- 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);
-
- if (!match) {
- return null;
- }
-
- 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;
- }();
-
-// 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;
-
- 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+)/);
-
- 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;
- }
-
- return version;
- }();
-
- 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
- });
-
- 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;
- };
-
-
-
-
-
-
-
-
-
-
-
- var classCallCheck = function (instance, Constructor) {
- if (!(instance instanceof Constructor)) {
- throw new TypeError("Cannot call a class as a function");
- }
- };
-
-
-
-
-
-
-
-
-
-
-
- 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);
- }
-
- 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;
- };
-
-
-
-
-
-
-
-
-
-
-
- var possibleConstructorReturn = function (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 taggedTemplateLiteralLoose = function (strings, raw) {
- strings.raw = raw;
- return strings;
- };
-
- /**
- * @file obj.js
- * @module obj
- */
-
- /**
- * @callback obj:EachCallback
- *
- * @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
- */
-
- /**
- * @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;
-
- /**
- * 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);
- });
- }
-
- /**
- * 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;
-
- return keys(object).reduce(function (accum, key) {
- return fn(accum, object[key], key);
- }, initial);
- }
-
- /**
- * 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];
- }
-
- if (Object.assign) {
- return Object.assign.apply(Object, [target].concat(sources));
- }
-
- sources.forEach(function (source) {
- if (!source) {
- return;
- }
-
- each(source, function (value, key) {
- target[key] = value;
- });
- });
-
- return target;
- }
-
- /**
- * 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';
- }
-
- /**
- * 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;
- }
-
- /**
- * @file log.js
- * @module log
- */
- var log = void 0;
-
-// This is the private tracking variable for logging level.
- var level = 'info';
-
-// This is the private tracking variable for the logging history.
- var history = [];
-
- /**
- * 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;
-
- var lvl = log.levels[level];
- var lvlRegExp = new RegExp('^(' + lvl + ')$');
-
- if (type !== 'log') {
-
- // 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));
- }
-
- // Add console prefix after adding to history.
- args.unshift('VIDEOJS:');
-
- // If there's no console then don't try to output messages, but they will
- // still be stored in history.
- if (!window_1.console) {
- return;
- }
-
- // 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[type];
-
- if (!fn && type === 'debug') {
- // Certain browsers don't have support for console.debug. For those, we
- // should default to the closest comparable log.
- fn = window_1.console.info || window_1.console.log;
- }
-
- // 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;
- }
-
- // 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);
- }
- }
-
- // 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(' ');
- }
-
- // 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);
- }
- };
-
- /**
- * 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);
- };
-
- /**
- * 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`: Matches only Video.js-provided functions (`debug`, `log`,
- * `log.warn`, and `log.error`).
- * - `debug`: Matches `log.debug`, `log`, `log.warn`, and `log.error` calls.
- * - `info` (default): Matches `log`, `log.warn`, and `log.error` calls.
- * - `warn`: Matches `log.warn` and `log.error` calls.
- * - `error`: Matches only `log.error` calls.
- *
- * @type {Object}
- */
- log.levels = {
- all: 'debug|log|warn|error',
- off: '',
- debug: 'debug|log|warn|error',
- info: 'log|warn|error',
- warn: 'warn|error',
- error: 'error',
- DEFAULT: level
- };
-
- /**
- * 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');
- }
- level = lvl;
- }
- return level;
- };
-
- /**
- * 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) : [];
- };
-
- /**
- * 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;
- }
- };
-
- /**
- * Enable history tracking if it is currently disabled.
- */
- log.history.enable = function () {
- if (history === null) {
- history = [];
- }
- };
-
- /**
- * 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);
- };
-
- /**
- * 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];
- }
-
- return logByType('warn', args);
- };
-
- /**
- * Logs debug messages. Similar to `console.debug`, but may also act as a comparable
- * log if `console.debug` is not available
- *
- * @param {Mixed[]} args
- * One or more messages or objects that should be logged as debug.
- */
- log.debug = function () {
- for (var _len4 = arguments.length, args = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {
- args[_key4] = arguments[_key4];
- }
-
- return logByType('debug', args);
- };
-
- var log$1 = log;
-
- function clean (s) {
- return s.replace(/\n\r?\s*/g, '')
- }
-
-
- var tsml = function tsml (sa) {
- var s = ''
- , i = 0;
-
- for (; i < arguments.length; i++)
- s += clean(sa[i]) + (arguments[i + 1] || '');
-
- return s
- };
-
- /**
- * @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 '';
- }
-
- if (typeof window_1.getComputedStyle === 'function') {
- var cs = window_1.getComputedStyle(el);
-
- return cs ? cs[prop] : '';
- }
-
- return el.currentStyle[prop] || '';
- }
-
- 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 ', '.']);
-
- /**
- * @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);
- }
-
- /**
- * 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');
- }
- }
-
- /**
- * 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)');
- }
-
- /**
- * Whether the current DOM interface appears to be real.
- *
- * @return {Boolean}
- */
- function isReal() {
- return (
-
- // Both document and window will never be undefined thanks to `global`.
- document_1 === window_1.document &&
-
- // 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'
- );
- }
-
- /**
- * 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;
- }
-
- /**
- * 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;
- }
- }
-
- /**
- * Creates functions to query the DOM using a given method.
- *
- * @param {string} method
- * The method to create the query with.
- *
- * @return {Function}
- * The query method
- */
- 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;
-
- return ctx[method] && ctx[method](selector);
- };
- }
-
- /**
- * 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);
-
- Object.getOwnPropertyNames(properties).forEach(function (propName) {
- var val = properties[propName];
-
- // 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);
-
- // 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;
- }
- });
-
- Object.getOwnPropertyNames(attributes).forEach(function (attrName) {
- el.setAttribute(attrName, attributes[attrName]);
- });
-
- if (content) {
- appendContent(el, content);
- }
-
- return el;
- }
-
- /**
- * 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;
- }
-
- /**
- * 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);
- }
- }
-
- /**
- * 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);
- }
-
- /**
- * 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);
-
- // 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();
- }
-
- return element;
- }
-
- /**
- * 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(' ');
- }
-
- return element;
- }
-
- /**
- * 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
- */
-
- /**
- * 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) {
-
- // 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);
-
- if (typeof predicate === 'function') {
- predicate = predicate(element, classToToggle);
- }
-
- if (typeof predicate !== 'boolean') {
- predicate = !has;
- }
-
- // If the necessary class operation matches the current state of the
- // element, no action is required.
- if (predicate === has) {
- return;
- }
-
- if (predicate) {
- addClass(element, classToToggle);
- } else {
- removeClass(element, classToToggle);
- }
-
- return element;
- }
-
- /**
- * 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);
- }
- });
- }
-
- /**
- * 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.
- *
- * @param {Element} tag
- * Element from which to get tag attributes.
- *
- * @return {Object}
- * All attributes of the element.
- */
- function getAttributes(tag) {
- var obj = {};
-
- // 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' + ',';
-
- if (tag && tag.attributes && tag.attributes.length > 0) {
- var attrs = tag.attributes;
-
- 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;
- }
- }
-
- return obj;
- }
-
- /**
- * 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);
- }
-
- /**
- * 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);
- }
-
- /**
- * Remove an element's attribute
- *
- * @param {Element} el
- * A DOM element
- *
- * @param {string} attribute
- * Attribute to remove
- */
- function removeAttribute(el, attribute) {
- el.removeAttribute(attribute);
- }
-
- /**
- * Attempt to block the ability to select text while dragging controls
- */
- function blockTextSelection() {
- document_1.body.focus();
- document_1.onselectstart = function () {
- return false;
- };
- }
-
- /**
- * Turn off text selection blocking
- */
- function unblockTextSelection() {
- document_1.onselectstart = function () {
- return true;
- };
- }
-
- /**
- * 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 = {};
-
- ['bottom', 'height', 'left', 'right', 'top', 'width'].forEach(function (k) {
- if (rect[k] !== undefined) {
- result[k] = rect[k];
- }
- });
-
- if (!result.height) {
- result.height = parseFloat(computedStyle(el, 'height'));
- }
-
- if (!result.width) {
- result.width = parseFloat(computedStyle(el, 'width'));
- }
-
- 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
- */
-
- /**
- * 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;
-
- if (el.getBoundingClientRect && el.parentNode) {
- box = el.getBoundingClientRect();
- }
-
- if (!box) {
- return {
- left: 0,
- top: 0
- };
- }
-
- var docEl = document_1.documentElement;
- var body = document_1.body;
-
- var clientLeft = docEl.clientLeft || body.clientLeft || 0;
- var scrollLeft = window_1.pageXOffset || body.scrollLeft;
- var left = box.left + scrollLeft - clientLeft;
-
- var clientTop = docEl.clientTop || body.clientTop || 0;
- var scrollTop = window_1.pageYOffset || body.scrollTop;
- var top = box.top + scrollTop - clientTop;
-
- // Android sometimes returns slightly off decimal values, so need to round
- return {
- left: Math.round(left),
- top: Math.round(top)
- };
- }
-
- /**
- * 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
- */
-
- /**
- * 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;
-
- 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;
- }
-
- position.y = Math.max(0, Math.min(1, (boxY - pageY + boxH) / boxH));
- position.x = Math.max(0, Math.min(1, (pageX - boxX) / boxW));
-
- 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;
- }
-
- /**
- * 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;
- }
-
- /**
- * 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();
- }
-
- // 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) {
-
- // 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();
- }
-
- if (isEl(value) || isTextNode(value)) {
- return value;
- }
-
- if (typeof value === 'string' && /\S/.test(value)) {
- return document_1.createTextNode(value);
- }
- }).filter(function (value) {
- return value;
- });
- }
-
- /**
- * 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;
- }
-
- /**
- * 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);
- }
-
- /**
- * Check if event was a single left click
- *
- * @param {EventTarget~Event} event
- * Event object
- *
- * @return {boolean}
- * - True if a left click
- * - False if not a left click
- */
- function isSingleLeftClick(event) {
- // Note: if you create something draggable, be sure to
- // call it on both `mousedown` and `mousemove` event,
- // otherwise `mousedown` should be enough for a button
-
- if (event.button === undefined && event.buttons === undefined) {
- // Why do we need `butttons` ?
- // Because, middle mouse sometimes have this:
- // e.button === 0 and e.buttons === 4
- // Furthermore, we want to prevent combination click, something like
- // HOLD middlemouse then left click, that would be
- // e.button === 0, e.buttons === 5
- // just `button` is not gonna work
-
- // Alright, then what this block does ?
- // this is for chrome `simulate mobile devices`
- // I want to support this as well
-
- return true;
- }
-
- if (event.button === 0 && event.buttons === undefined) {
- // Touch screen, sometimes on some specific device, `buttons`
- // doesn't have anything (safari on ios, blackberry...)
-
- return true;
- }
-
- if (IE_VERSION === 9) {
- // Ignore IE9
-
- return true;
- }
-
- if (event.button !== 0 || event.buttons !== 1) {
- // This is the reason we have those if else block above
- // if any special case we can catch and let it slide
- // we do it above, when get to here, this definitely
- // is-not-left-click
-
- return false;
- }
-
- return true;
- }
-
- /**
- * 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');
-
- /**
- * 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,
- isSingleLeftClick: isSingleLeftClick,
- $: $,
- $$: $$
- });
-
- /**
- * @file guid.js
- * @module guid
- */
-
- /**
- * Unique ID for an element or function
- * @type {Number}
- */
- var _guid = 1;
-
- /**
- * 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 = {};
-
- /*
- * Unique attribute name to store an element's guid in
- *
- * @type {String}
- * @constant
- * @private
- */
- var elIdAttr = 'vdata' + new Date().getTime();
-
- /**
- * 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 (!id) {
- id = el[elIdAttr] = newGUID();
- }
-
- if (!elData[id]) {
- elData[id] = {};
- }
-
- return elData[id];
- }
-
- /**
- * 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];
-
- if (!id) {
- return false;
- }
-
- return !!Object.getOwnPropertyNames(elData[id]).length;
- }
-
- /**
- * 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];
-
- if (!id) {
- return;
- }
-
- // Remove all stored data
- delete elData[id];
-
- // Remove the elIdAttr property from the DOM node
- try {
- delete el[elIdAttr];
- } catch (e) {
- if (el.removeAttribute) {
- el.removeAttribute(elIdAttr);
- } else {
- // IE doesn't appear to support removeAttribute on the document element
- el[elIdAttr] = null;
- }
- }
- }
-
- /**
- * @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
- */
-
- /**
- * 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);
-
- // 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
-
- // 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);
- }
- }
-
- // 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;
- }
-
- // Finally remove the element data if there is no data left
- if (Object.getOwnPropertyNames(data).length === 0) {
- removeData(elem);
- }
- }
-
- /**
- * 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);
- });
- }
-
- /**
- * 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;
- }
-
- // 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];
- }
- }
- }
-
- // The event occurred on this element
- if (!event.target) {
- event.target = event.srcElement || document_1;
- }
-
- // Handle which other element the event is related to
- if (!event.relatedTarget) {
- event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
- }
-
- // Stop the default browser action
- event.preventDefault = function () {
- if (old.preventDefault) {
- old.preventDefault();
- }
- event.returnValue = false;
- old.returnValue = false;
- event.defaultPrevented = true;
- };
-
- 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);
- }
-
- // Handle key presses
- event.which = event.charCode || event.keyCode;
-
- // Fix button for mouse clicks:
- // 0 == left; 1 == middle; 2 == right
- if (event.button !== null && event.button !== undefined) {
-
- // 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 */
- }
- }
-
- // Returns fixed-up instance
- return event;
- }
-
- /**
- * Whether passive event listeners are supported
- */
- var _supportsPassive = false;
-
- (function () {
- try {
- var opts = Object.defineProperty({}, 'passive', {
- get: function get() {
- _supportsPassive = true;
- }
- });
-
- window_1.addEventListener('test', null, opts);
- window_1.removeEventListener('test', null, opts);
- } catch (e) {
- // disregard
- }
- })();
-
- /**
- * Touch events Chrome expects to be passive
- */
- var passiveEvents = ['touchstart', 'touchmove'];
-
- /**
- * 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);
- }
-
- var data = getData(elem);
-
- // We need a place to store all our handler data
- if (!data.handlers) {
- data.handlers = {};
- }
-
- if (!data.handlers[type]) {
- data.handlers[type] = [];
- }
-
- if (!fn.guid) {
- fn.guid = newGUID();
- }
-
- data.handlers[type].push(fn);
-
- if (!data.dispatcher) {
- data.disabled = false;
-
- data.dispatcher = function (event, hash) {
-
- if (data.disabled) {
- return;
- }
-
- event = fixEvent(event);
-
- var handlers = data.handlers[event.type];
-
- if (handlers) {
- // Copy handlers so if handlers are added/removed during the process it doesn't throw everything off.
- var handlersCopy = handlers.slice(0);
-
- 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);
- }
- }
- }
- }
- };
- }
-
- 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);
- }
- }
- }
-
- /**
- * 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;
- }
-
- var data = getData(elem);
-
- // If no events exist, nothing to unbind
- if (!data.handlers) {
- return;
- }
-
- if (Array.isArray(type)) {
- return _handleMultipleEvents(off, elem, type, fn);
- }
-
- // Utility function
- var removeType = function removeType(el, t) {
- data.handlers[t] = [];
- _cleanUpEvents(el, t);
- };
-
- // Are we removing all bound events?
- if (type === undefined) {
- for (var t in data.handlers) {
- if (Object.prototype.hasOwnProperty.call(data.handlers || {}, t)) {
- removeType(elem, t);
- }
- }
- return;
- }
-
- var handlers = data.handlers[type];
-
- // If no handlers exist, nothing to unbind
- if (!handlers) {
- return;
- }
-
- // If no listener was provided, remove all listeners for type
- if (!fn) {
- removeType(elem, type);
- return;
- }
-
- // 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);
- }
- }
- }
-
- _cleanUpEvents(elem, type);
- }
-
- /**
- * 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);
- }
-
- // 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);
-
- // If at the top of the DOM, triggers the default action unless disabled.
- } else if (!parent && !event.defaultPrevented) {
- var targetData = getData(event.target);
-
- // 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;
- }
- }
-
- // 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);
- };
-
- // 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
- });
-
- /**
- * @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;
-
- /**
- * Set up any tags that have a data-setup `attribute` when the player is started.
- */
- var autoSetup = function autoSetup() {
-
- // Protect against breakage in non-browser environments.
- if (!isReal()) {
- return;
- }
-
- // 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);
-
- // 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 divs = document_1.getElementsByTagName('video-js');
- var mediaEls = [];
-
- 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]);
- }
- }
-
- if (divs && divs.length > 0) {
- for (var _i2 = 0, _e2 = divs.length; _i2 < _e2; _i2++) {
- mediaEls.push(divs[_i2]);
- }
- }
-
- // Check if any media elements exist
- if (mediaEls && mediaEls.length > 0) {
-
- for (var _i3 = 0, _e3 = mediaEls.length; _i3 < _e3; _i3++) {
- var mediaEl = mediaEls[_i3];
-
- // 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) {
-
- // Make sure this player hasn't already been set up.
- if (mediaEl.player === undefined) {
- var options = mediaEl.getAttribute('data-setup');
-
- // 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 {
- autoSetupTimeout(1);
- break;
- }
- }
-
- // 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 {
- /**
- * Listen for the load event on window, and set _windowLoaded to true.
- *
- * @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');
-
- style.className = className;
-
- return style;
- };
-
- /**
- * 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;
- }
- };
-
- /**
- * @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();
- }
-
- // Create the new function that changes the context
- var bound = function bound() {
- return fn.apply(context, arguments);
- };
-
- // 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;
-
- return bound;
- };
-
- /**
- * 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();
-
- if (now - last >= wait) {
- fn.apply(undefined, arguments);
- last = now;
- }
- };
-
- return throttled;
- };
-
- /**
- * @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}
- */
-
- /**
- * 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
- */
-
- /**
- * 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;
-
- this.addEventListener = function () {};
- on(this, type, fn);
- this.addEventListener = ael;
- };
-
- /**
- * 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);
- };
-
- /**
- * 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;
-
- /**
- * 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;
- };
-
- /**
- * 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;
-
- if (typeof event === 'string') {
- event = { type: type };
- }
- event = fixEvent(event);
-
- if (this.allowedEvents_[type] && this['on' + type]) {
- this['on' + type](event);
- }
-
- trigger(this, event);
- };
-
- /**
- * 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';
- });
- };
-
- /**
- * 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
- );
- };
-
- /**
- * 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.');
- }
- };
-
- /**
- * 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.');
- }
- };
-
- /**
- * 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;
-
- if (isTargetingSelf) {
- target = self.eventBusEl_;
-
- // 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];
- }
-
- validateTarget(target);
- validateEventType(type);
- validateListener(listener);
-
- listener = bind(self, listener);
-
- return { isTargetingSelf: isTargetingSelf, target: target, type: type, listener: listener };
- };
-
- /**
- * 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 = {
-
- /**
- * Add a listener to an event (or events) on this object or another evented
- * object.
- *
- * @param {string|Array|Element|Object} targetOrType
- * If this is a string or array, it represents the event type(s)
- * that will trigger the listener.
- *
- * Another evented object can be passed here instead, which will
- * cause the listener to listen for events on _that_ object.
- *
- * 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];
- }
-
- var _normalizeListenArgs = normalizeListenArgs(this, args),
- isTargetingSelf = _normalizeListenArgs.isTargetingSelf,
- target = _normalizeListenArgs.target,
- type = _normalizeListenArgs.type,
- listener = _normalizeListenArgs.listener;
-
- listen(target, 'on', type, listener);
-
- // If this object is listening to another evented object.
- if (!isTargetingSelf) {
-
- // If this object is disposed, remove the listener.
- var removeListenerOnDispose = function removeListenerOnDispose() {
- return _this.off(target, type, listener);
- };
-
- // 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);
- }
- },
-
-
- /**
- * 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.
- *
- * @param {string|Array|Element|Object} targetOrType
- * If this is a string or array, it represents the event type(s)
- * that will trigger the listener.
- *
- * Another evented object can be passed here instead, which will
- * cause the listener to listen for events on _that_ object.
- *
- * 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.
- */
- one: function one$$1() {
- var _this2 = this;
-
- for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
- args[_key2] = arguments[_key2];
- }
-
- var _normalizeListenArgs2 = normalizeListenArgs(this, args),
- isTargetingSelf = _normalizeListenArgs2.isTargetingSelf,
- target = _normalizeListenArgs2.target,
- type = _normalizeListenArgs2.type,
- listener = _normalizeListenArgs2.listener;
-
- // Targeting this evented object.
-
-
- if (isTargetingSelf) {
- listen(target, 'one', type, listener);
-
- // 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];
- }
-
- _this2.off(target, type, wrapper);
- listener.apply(null, largs);
- };
-
- // 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);
- }
- },
-
-
- /**
- * Removes listener(s) from event(s) on an evented object.
- *
- * @param {string|Array|Element|Object} [targetOrType]
- * If this is a string or array, it represents the event type(s).
- *
- * 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);
-
- // Targeting another evented object.
- } else {
- var target = targetOrType;
- var type = typeOrListener;
-
- // Fail fast and in a meaningful way!
- validateTarget(target);
- validateEventType(type);
- validateListener(listener);
-
- // 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);
- }
- }
- },
-
-
- /**
- * Fire an event on this evented object, causing its listeners to be called.
- *
- * @param {string|Object} event
- * An event type or an object with a type property.
- *
- * @param {Object} [hash]
- * An additional object to pass along to listeners.
- *
- * @returns {boolean}
- * Whether or not the default behavior was prevented.
- */
- trigger: function trigger$$1(event, hash) {
- return trigger(this.eventBusEl_, event, hash);
- }
- };
-
- /**
- * 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_.
-
- 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' });
- }
-
- assign(target, EventedMixin);
-
- // When any evented object is disposed, it removes all its listeners.
- target.on('dispose', function () {
- target.off();
- window_1.setTimeout(function () {
- target.eventBusEl_ = null;
- }, 0);
- });
-
- 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 = {
-
- /**
- * A hash containing arbitrary keys and values representing the state of
- * the object.
- *
- * @type {Object}
- */
- state: {},
-
- /**
- * 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();
- }
-
- var changes = void 0;
-
- each(stateUpdates, function (value, key) {
-
- // 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;
- });
-
- // 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)) {
-
- /**
- * 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'
- });
- }
-
- return changes;
- }
- };
-
- /**
- * 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 happens after the mixing-in because we need to replace the `state`
- // added in that step.
- target.state = assign({}, target.state, defaultState);
-
- // Auto-bind the `handleStateChanged` method of the target object if it exists.
- if (typeof target.handleStateChanged === 'function' && isEvented(target)) {
- target.on('statechanged', target.handleStateChanged);
- }
-
- return target;
- }
-
- /**
- * @file to-title-case.js
- * @module to-title-case
- */
-
- /**
- * 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;
- }
-
- return string.charAt(0).toUpperCase() + string.slice(1);
- }
-
- /**
- * 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);
- }
-
- /**
- * @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];
- }
-
- sources.forEach(function (source) {
- if (!source) {
- return;
- }
-
- each(source, function (value, key) {
- if (!isPlain(value)) {
- result[key] = value;
- return;
- }
-
- if (!isPlain(result[key])) {
- result[key] = {};
- }
-
- result[key] = mergeOptions(result[key], value);
- });
- });
-
- return result;
- }
-
- /**
- * Player Component - Base class for all UI objects
- *
- * @file component.js
- */
- /**
- * Base class for all UI Components.
- * Components are UI objects which represent both a javascript object and an element
- * in the DOM. They can be children of other components, and can have
- * children themselves.
- *
- * Components can also use methods from {@link EventTarget}
- */
-
- var Component = function () {
-
- /**
- * A callback that is called when a component is ready. Does not have any
- * paramters and any callback value will be ignored.
- *
- * @callback Component~ReadyCallback
- * @this Component
- */
-
- /**
- * Creates an instance of this class.
- *
- * @param {Player} player
- * The `Player` that this class should be attached to.
- *
- * @param {Object} [options]
- * The key/value store of player options.
- *
- * @param {Object[]} [options.children]
- * An array of children objects to intialize this component with. Children objects have
- * a name property that will be used if more than one component of the same type needs to be
- * added.
- *
- * @param {Component~ReadyCallback} [ready]
- * Function that gets called when the `Component` is ready.
- */
- function Component(player, options, ready) {
- classCallCheck(this, Component);
-
-
- // The component might be the player itself and we can't pass `this` to super
- if (!player && this.play) {
- this.player_ = player = this; // eslint-disable-line
- } else {
- this.player_ = player;
- }
-
- // Make a copy of prototype.options_ to protect against overriding defaults
- this.options_ = mergeOptions({}, this.options_);
-
- // Updated options with supplied options
- options = this.options_ = mergeOptions(this.options_, options);
-
- // Get ID from options or options element if one is supplied
- this.id_ = options.id || options.el && options.el.id;
-
- // If there was no ID from the options, generate one
- if (!this.id_) {
- // Don't require the player ID function in the case of mock players
- var id = player && player.id && player.id() || 'no_player';
-
- this.id_ = id + '_component_' + 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();
- }
-
- // if evented is anything except false, we want to mixin in evented
- if (options.evented !== false) {
- // 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();
- }
- }
-
- /**
- * Dispose of the `Component` and all child components.
- *
- * @fires Component#dispose
- */
-
-
- Component.prototype.dispose = function dispose() {
-
- /**
- * Triggered when a `Component` is disposed.
- *
- * @event Component#dispose
- * @type {EventTarget~Event}
- *
- * @property {boolean} [bubbles=false]
- * set to false so that the close event does not
- * bubble up
- */
- this.trigger({ type: 'dispose', bubbles: false });
-
- // Dispose all children.
- if (this.children_) {
- for (var i = this.children_.length - 1; i >= 0; i--) {
- if (this.children_[i].dispose) {
- this.children_[i].dispose();
- }
- }
- }
-
- // Delete child references
- this.children_ = null;
- this.childIndex_ = null;
- this.childNameIndex_ = null;
-
- if (this.el_) {
- // Remove element from DOM
- if (this.el_.parentNode) {
- this.el_.parentNode.removeChild(this.el_);
- }
-
- removeData(this.el_);
- this.el_ = null;
- }
-
- // remove reference to the player after disposing of the element
- this.player_ = null;
- };
-
- /**
- * Return the {@link Player} that the `Component` has attached to.
- *
- * @return {Player}
- * The player that this `Component` has attached to.
- */
-
-
- Component.prototype.player = function player() {
- return this.player_;
- };
-
- /**
- * Deep merge of options objects with new options.
- * > Note: When both `obj` and `options` contain properties whose values are objects.
- * The two properties get merged using {@link module:mergeOptions}
- *
- * @param {Object} obj
- * The object that contains new options.
- *
- * @return {Object}
- * A new object of `this.options_` and `obj` merged together.
- *
- * @deprecated since version 5
- */
-
-
- Component.prototype.options = function options(obj) {
- log$1.warn('this.options() has been deprecated and will be moved to the constructor in 6.0');
-
- if (!obj) {
- return this.options_;
- }
-
- this.options_ = mergeOptions(this.options_, obj);
- return this.options_;
- };
-
- /**
- * Get the `Component`s DOM element
- *
- * @return {Element}
- * The DOM element for this `Component`.
- */
-
-
- Component.prototype.el = function el() {
- return this.el_;
- };
-
- /**
- * Create the `Component`s DOM element.
- *
- * @param {string} [tagName]
- * Element's DOM node type. e.g. 'div'
- *
- * @param {Object} [properties]
- * An object of properties that should be set.
- *
- * @param {Object} [attributes]
- * An object of attributes that should be set.
- *
- * @return {Element}
- * The element that gets created.
- */
-
-
- Component.prototype.createEl = function createEl$$1(tagName, properties, attributes) {
- return createEl(tagName, properties, attributes);
- };
-
- /**
- * Localize a string given the string in english.
- *
- * 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.
- *
- * 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.
- *
- * 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}');
- * ```
- *
- * Which outputs something like: `01:23 of 24:56`.
- *
- *
- * @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.prototype.localize = function localize(string, tokens) {
- var defaultValue = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : string;
-
- 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];
-
- var localizedString = defaultValue;
-
- if (language && language[string]) {
- localizedString = language[string];
- } else if (primaryLang && primaryLang[string]) {
- localizedString = primaryLang[string];
- }
-
- if (tokens) {
- localizedString = localizedString.replace(/\{(\d+)\}/g, function (match, index) {
- var value = tokens[index - 1];
- var ret = value;
-
- if (typeof value === 'undefined') {
- ret = match;
- }
-
- return ret;
- });
- }
-
- return localizedString;
- };
-
- /**
- * Return the `Component`s DOM element. This is where children get inserted.
- * This will usually be the the same as the element returned in {@link Component#el}.
- *
- * @return {Element}
- * The content element for this `Component`.
- */
-
-
- Component.prototype.contentEl = function contentEl() {
- return this.contentEl_ || this.el_;
- };
-
- /**
- * Get this `Component`s ID
- *
- * @return {string}
- * The id of this `Component`
- */
-
-
- Component.prototype.id = function id() {
- return this.id_;
- };
-
- /**
- * Get the `Component`s name. The name gets used to reference the `Component`
- * and is set during registration.
- *
- * @return {string}
- * The name of this `Component`.
- */
-
-
- Component.prototype.name = function name() {
- return this.name_;
- };
-
- /**
- * Get an array of all child components
- *
- * @return {Array}
- * The children
- */
-
-
- Component.prototype.children = function children() {
- return this.children_;
- };
-
- /**
- * Returns the child `Component` with the given `id`.
- *
- * @param {string} id
- * The id of the child `Component` to get.
- *
- * @return {Component|undefined}
- * The child `Component` with the given `id` or undefined.
- */
-
-
- Component.prototype.getChildById = function getChildById(id) {
- return this.childIndex_[id];
- };
-
- /**
- * Returns the child `Component` with the given `name`.
- *
- * @param {string} name
- * The name of the child `Component` to get.
- *
- * @return {Component|undefined}
- * The child `Component` with the given `name` or undefined.
- */
-
-
- Component.prototype.getChild = function getChild(name) {
- if (!name) {
- return;
- }
-
- name = toTitleCase(name);
-
- return this.childNameIndex_[name];
- };
-
- /**
- * Add a child `Component` inside the current `Component`.
- *
- *
- * @param {string|Component} child
- * The name or instance of a child to add.
- *
- * @param {Object} [options={}]
- * The key/value store of options that will get passed to children of
- * the child.
- *
- * @param {number} [index=this.children_.length]
- * The index to attempt to add a child into.
- *
- * @return {Component}
- * The `Component` that gets added as a child. When using a string the
- * `Component` will get created by this process.
- */
-
-
- Component.prototype.addChild = function addChild(child) {
- var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
- var index = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.children_.length;
-
- var component = void 0;
- var componentName = void 0;
-
- // If child is a string, create component with options
- if (typeof child === 'string') {
- componentName = toTitleCase(child);
-
- var componentClassName = options.componentClass || componentName;
-
- // Set name through options
- options.name = componentName;
-
- // Create a new object & element for this controls set
- // If there's no .player_, this is a player
- var ComponentClass = Component.getComponent(componentClassName);
-
- if (!ComponentClass) {
- throw new Error('Component ' + componentClassName + ' does not exist');
- }
-
- // data stored directly on the videojs object may be
- // misidentified as a component to retain
- // backwards-compatibility with 4.x. check to make sure the
- // component class can be instantiated.
- if (typeof ComponentClass !== 'function') {
- return null;
- }
-
- component = new ComponentClass(this.player_ || this, options);
-
- // child is a component instance
- } else {
- component = child;
- }
-
- this.children_.splice(index, 0, component);
-
- if (typeof component.id === 'function') {
- this.childIndex_[component.id()] = component;
- }
-
- // If a name wasn't used to create the component, check if we can use the
- // name function of the component
- componentName = componentName || component.name && toTitleCase(component.name());
-
- if (componentName) {
- this.childNameIndex_[componentName] = component;
- }
-
- // Add the UI object's element to the container div (box)
- // Having an element is not required
- if (typeof component.el === 'function' && component.el()) {
- var childNodes = this.contentEl().children;
- var refNode = childNodes[index] || null;
-
- this.contentEl().insertBefore(component.el(), refNode);
- }
-
- // Return so it can stored on parent object if desired.
- return component;
- };
-
- /**
- * Remove a child `Component` from this `Component`s list of children. Also removes
- * the child `Component`s element from this `Component`s element.
- *
- * @param {Component} component
- * The child `Component` to remove.
- */
-
-
- Component.prototype.removeChild = function removeChild(component) {
- if (typeof component === 'string') {
- component = this.getChild(component);
- }
-
- if (!component || !this.children_) {
- return;
- }
-
- var childFound = false;
-
- for (var i = this.children_.length - 1; i >= 0; i--) {
- if (this.children_[i] === component) {
- childFound = true;
- this.children_.splice(i, 1);
- break;
- }
- }
-
- if (!childFound) {
- return;
- }
-
- this.childIndex_[component.id()] = null;
- this.childNameIndex_[component.name()] = null;
-
- var compEl = component.el();
-
- if (compEl && compEl.parentNode === this.contentEl()) {
- this.contentEl().removeChild(component.el());
- }
- };
-
- /**
- * Add and initialize default child `Component`s based upon options.
- */
-
-
- Component.prototype.initChildren = function initChildren() {
- var _this = this;
-
- var children = this.options_.children;
-
- if (children) {
- // `this` is `parent`
- var parentOptions = this.options_;
-
- var handleAdd = function handleAdd(child) {
- var name = child.name;
- var opts = child.opts;
-
- // Allow options for children to be set at the parent options
- // e.g. videojs(id, { controlBar: false });
- // instead of videojs(id, { children: { controlBar: false });
- if (parentOptions[name] !== undefined) {
- opts = parentOptions[name];
- }
-
- // Allow for disabling default components
- // e.g. options['children']['posterImage'] = false
- if (opts === false) {
- return;
- }
-
- // Allow options to be passed as a simple boolean if no configuration
- // is necessary.
- if (opts === true) {
- opts = {};
- }
-
- // We also want to pass the original player options
- // to each component as well so they don't need to
- // reach back into the player for options later.
- opts.playerOptions = _this.options_.playerOptions;
-
- // Create and add the child component.
- // Add a direct reference to the child by name on the parent instance.
- // If two of the same component are used, different names should be supplied
- // for each
- var newChild = _this.addChild(name, opts);
-
- if (newChild) {
- _this[name] = newChild;
- }
- };
-
- // Allow for an array of children details to passed in the options
- var workingChildren = void 0;
- var Tech = Component.getComponent('Tech');
-
- if (Array.isArray(children)) {
- workingChildren = children;
- } else {
- workingChildren = Object.keys(children);
- }
-
- workingChildren
- // children that are in this.options_ but also in workingChildren would
- // give us extra children we do not want. So, we want to filter them out.
- .concat(Object.keys(this.options_).filter(function (child) {
- return !workingChildren.some(function (wchild) {
- if (typeof wchild === 'string') {
- return child === wchild;
- }
- return child === wchild.name;
- });
- })).map(function (child) {
- var name = void 0;
- var opts = void 0;
-
- if (typeof child === 'string') {
- name = child;
- opts = children[name] || _this.options_[name] || {};
- } else {
- name = child.name;
- opts = child;
- }
-
- return { name: name, opts: opts };
- }).filter(function (child) {
- // we have to make sure that child.name isn't in the techOrder since
- // techs are registerd as Components but can't aren't compatible
- // See https://github.com/videojs/video.js/issues/2772
- var c = Component.getComponent(child.opts.componentClass || toTitleCase(child.name));
-
- return c && !Tech.isTech(c);
- }).forEach(handleAdd);
- }
- };
-
- /**
- * Builds the default DOM class name. Should be overriden by sub-components.
- *
- * @return {string}
- * The DOM class name for this object.
- *
- * @abstract
- */
-
-
- Component.prototype.buildCSSClass = function buildCSSClass() {
- // Child classes can include a function that does:
- // return 'CLASS NAME' + this._super();
- return '';
- };
-
- /**
- * 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.
- */
-
-
- Component.prototype.ready = function ready(fn) {
- var sync = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
-
- if (!fn) {
- return;
- }
-
- if (!this.isReady_) {
- this.readyQueue_ = this.readyQueue_ || [];
- this.readyQueue_.push(fn);
- return;
- }
-
- if (sync) {
- fn.call(this);
- } else {
- // Call the function asynchronously by default for consistency
- this.setTimeout(fn, 1);
- }
- };
-
- /**
- * Trigger all the ready listeners for this `Component`.
- *
- * @fires Component#ready
- */
-
-
- Component.prototype.triggerReady = function triggerReady() {
- this.isReady_ = true;
-
- // Ensure ready is triggerd asynchronously
- this.setTimeout(function () {
- var readyQueue = this.readyQueue_;
-
- // Reset Ready Queue
- this.readyQueue_ = [];
-
- if (readyQueue && readyQueue.length > 0) {
- readyQueue.forEach(function (fn) {
- fn.call(this);
- }, this);
- }
-
- // Allow for using event listeners also
- /**
- * Triggered when a `Component` is ready.
- *
- * @event Component#ready
- * @type {EventTarget~Event}
- */
- this.trigger('ready');
- }, 1);
- };
-
- /**
- * Find a single DOM element matching a `selector`. This can be within the `Component`s
- * `contentEl()` or another custom context.
- *
- * @param {string} selector
- * A valid CSS selector, which will be passed to `querySelector`.
- *
- * @param {Element|string} [context=this.contentEl()]
- * A DOM element within which to query. Can also be a selector string in
- * which case the first matching element will get used as context. If
- * missing `this.contentEl()` gets used. If `this.contentEl()` returns
- * nothing it falls back to `document`.
- *
- * @return {Element|null}
- * the dom element that was found, or null
- *
- * @see [Information on CSS Selectors](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Getting_Started/Selectors)
- */
-
-
- Component.prototype.$ = function $$$1(selector, context) {
- return $(selector, context || this.contentEl());
- };
-
- /**
- * Finds all DOM element matching a `selector`. This can be within the `Component`s
- * `contentEl()` or another custom context.
- *
- * @param {string} selector
- * A valid CSS selector, which will be passed to `querySelectorAll`.
- *
- * @param {Element|string} [context=this.contentEl()]
- * A DOM element within which to query. Can also be a selector string in
- * which case the first matching element will get used as context. If
- * missing `this.contentEl()` gets used. If `this.contentEl()` returns
- * nothing it falls back to `document`.
- *
- * @return {NodeList}
- * a list of dom elements that were found
- *
- * @see [Information on CSS Selectors](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Getting_Started/Selectors)
- */
-
-
- Component.prototype.$$ = function $$$$1(selector, context) {
- return $$(selector, context || this.contentEl());
- };
-
- /**
- * Check if a component's element has a CSS class name.
- *
- * @param {string} classToCheck
- * CSS class name to check.
- *
- * @return {boolean}
- * - True if the `Component` has the class.
- * - False if the `Component` does not have the class`
- */
-
-
- Component.prototype.hasClass = function hasClass$$1(classToCheck) {
- return hasClass(this.el_, classToCheck);
- };
-
- /**
- * Add a CSS class name to the `Component`s element.
- *
- * @param {string} classToAdd
- * CSS class name to add
- */
-
-
- Component.prototype.addClass = function addClass$$1(classToAdd) {
- addClass(this.el_, classToAdd);
- };
-
- /**
- * Remove a CSS class name from the `Component`s element.
- *
- * @param {string} classToRemove
- * CSS class name to remove
- */
-
-
- Component.prototype.removeClass = function removeClass$$1(classToRemove) {
- removeClass(this.el_, classToRemove);
- };
-
- /**
- * 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
- */
-
-
- Component.prototype.toggleClass = function toggleClass$$1(classToToggle, predicate) {
- toggleClass(this.el_, classToToggle, predicate);
- };
-
- /**
- * Show the `Component`s element if it is hidden by removing the
- * 'vjs-hidden' class name from it.
- */
-
-
- Component.prototype.show = function show() {
- this.removeClass('vjs-hidden');
- };
-
- /**
- * Hide the `Component`s element if it is currently showing by adding the
- * 'vjs-hidden` class name to it.
- */
-
-
- Component.prototype.hide = function hide() {
- this.addClass('vjs-hidden');
- };
-
- /**
- * Lock a `Component`s element in its visible state by adding the 'vjs-lock-showing'
- * class name to it. Used during fadeIn/fadeOut.
- *
- * @private
- */
-
-
- Component.prototype.lockShowing = function lockShowing() {
- this.addClass('vjs-lock-showing');
- };
-
- /**
- * Unlock a `Component`s element from its visible state by removing the 'vjs-lock-showing'
- * class name from it. Used during fadeIn/fadeOut.
- *
- * @private
- */
-
-
- Component.prototype.unlockShowing = function unlockShowing() {
- this.removeClass('vjs-lock-showing');
- };
-
- /**
- * Get the value of an attribute on the `Component`s element.
- *
- * @param {string} attribute
- * Name of the attribute to get the value from.
- *
- * @return {string|null}
- * - The value of the attribute that was asked for.
- * - Can be an empty string on some browsers if the attribute does not exist
- * or has no value
- * - Most browsers will return null if the attibute does not exist or has
- * no value.
- *
- * @see [DOM API]{@link https://developer.mozilla.org/en-US/docs/Web/API/Element/getAttribute}
- */
-
-
- Component.prototype.getAttribute = function getAttribute$$1(attribute) {
- return getAttribute(this.el_, attribute);
- };
-
- /**
- * Set the value of an attribute on the `Component`'s element
- *
- * @param {string} attribute
- * Name of the attribute to set.
- *
- * @param {string} value
- * Value to set the attribute to.
- *
- * @see [DOM API]{@link https://developer.mozilla.org/en-US/docs/Web/API/Element/setAttribute}
- */
-
-
- Component.prototype.setAttribute = function setAttribute$$1(attribute, value) {
- setAttribute(this.el_, attribute, value);
- };
-
- /**
- * Remove an attribute from the `Component`s element.
- *
- * @param {string} attribute
- * Name of the attribute to remove.
- *
- * @see [DOM API]{@link https://developer.mozilla.org/en-US/docs/Web/API/Element/removeAttribute}
- */
-
-
- Component.prototype.removeAttribute = function removeAttribute$$1(attribute) {
- removeAttribute(this.el_, attribute);
- };
-
- /**
- * Get or set the width of the component based upon the CSS styles.
- * See {@link Component#dimension} for more detailed information.
- *
- * @param {number|string} [num]
- * The width that you want to set postfixed with '%', 'px' or nothing.
- *
- * @param {boolean} [skipListeners]
- * Skip the componentresize event trigger
- *
- * @return {number|string}
- * The width when getting, zero if there is no width. Can be a string
- * postpixed with '%' or 'px'.
- */
-
-
- Component.prototype.width = function width(num, skipListeners) {
- return this.dimension('width', num, skipListeners);
- };
-
- /**
- * Get or set the height of the component based upon the CSS styles.
- * See {@link Component#dimension} for more detailed information.
- *
- * @param {number|string} [num]
- * The height that you want to set postfixed with '%', 'px' or nothing.
- *
- * @param {boolean} [skipListeners]
- * Skip the componentresize event trigger
- *
- * @return {number|string}
- * The width when getting, zero if there is no width. Can be a string
- * postpixed with '%' or 'px'.
- */
-
-
- Component.prototype.height = function height(num, skipListeners) {
- return this.dimension('height', num, skipListeners);
- };
-
- /**
- * Set both the width and height of the `Component` element at the same time.
- *
- * @param {number|string} width
- * Width to set the `Component`s element to.
- *
- * @param {number|string} height
- * Height to set the `Component`s element to.
- */
-
-
- Component.prototype.dimensions = function dimensions(width, height) {
- // Skip componentresize listeners on width for optimization
- this.width(width, true);
- this.height(height);
- };
-
- /**
- * Get or set width or height of the `Component` element. This is the shared code
- * for the {@link Component#width} and {@link Component#height}.
- *
- * Things to know:
- * - If the width or height in an number this will return the number postfixed with 'px'.
- * - If the width/height is a percent this will return the percent postfixed with '%'
- * - Hidden elements have a width of 0 with `window.getComputedStyle`. This function
- * defaults to the `Component`s `style.width` and falls back to `window.getComputedStyle`.
- * See [this]{@link http://www.foliotek.com/devblog/getting-the-width-of-a-hidden-element-with-jquery-using-width/}
- * for more information
- * - If you want the computed style of the component, use {@link Component#currentWidth}
- * and {@link {Component#currentHeight}
- *
- * @fires Component#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
- */
-
-
- Component.prototype.dimension = function dimension(widthOrHeight, num, skipListeners) {
- if (num !== undefined) {
- // Set to zero if null or literally NaN (NaN !== NaN)
- if (num === null || num !== num) {
- num = 0;
- }
-
- // Check if using css width/height (% or px) and adjust
- if (('' + num).indexOf('%') !== -1 || ('' + num).indexOf('px') !== -1) {
- this.el_.style[widthOrHeight] = num;
- } else if (num === 'auto') {
- this.el_.style[widthOrHeight] = '';
- } else {
- this.el_.style[widthOrHeight] = num + 'px';
- }
-
- // skipListeners allows us to avoid triggering the resize event when setting both width and height
- if (!skipListeners) {
- /**
- * Triggered when a component is resized.
- *
- * @event Component#componentresize
- * @type {EventTarget~Event}
- */
- this.trigger('componentresize');
- }
-
- return;
- }
-
- // Not setting a value, so getting it
- // Make sure element exists
- if (!this.el_) {
- return 0;
- }
-
- // Get dimension value from style
- var val = this.el_.style[widthOrHeight];
- var pxIndex = val.indexOf('px');
-
- if (pxIndex !== -1) {
- // Return the pixel value with no 'px'
- return parseInt(val.slice(0, pxIndex), 10);
- }
-
- // No px so using % or no style was set, so falling back to offsetWidth/height
- // If component has display:none, offset will return 0
- // TODO: handle display:none and no dimension style using px
- return parseInt(this.el_['offset' + toTitleCase(widthOrHeight)], 10);
- };
-
- /**
- * Get the width or the height of the `Component` elements computed style. Uses
- * `window.getComputedStyle`.
- *
- * @param {string} widthOrHeight
- * A string containing 'width' or 'height'. Whichever one you want to get.
- *
- * @return {number}
- * The dimension that gets asked for or 0 if nothing was set
- * for that dimension.
- */
-
-
- Component.prototype.currentDimension = function currentDimension(widthOrHeight) {
- var computedWidthOrHeight = 0;
-
- if (widthOrHeight !== 'width' && widthOrHeight !== 'height') {
- throw new Error('currentDimension only accepts width or height value');
- }
-
- if (typeof window_1.getComputedStyle === 'function') {
- var computedStyle = window_1.getComputedStyle(this.el_);
-
- computedWidthOrHeight = computedStyle.getPropertyValue(widthOrHeight) || computedStyle[widthOrHeight];
- }
-
- // remove 'px' from variable and parse as integer
- computedWidthOrHeight = parseFloat(computedWidthOrHeight);
-
- // if the computed value is still 0, it's possible that the browser is lying
- // and we want to check the offset values.
- // This code also runs on IE8 and wherever getComputedStyle doesn't exist.
- if (computedWidthOrHeight === 0) {
- var rule = 'offset' + toTitleCase(widthOrHeight);
-
- computedWidthOrHeight = this.el_[rule];
- }
-
- return computedWidthOrHeight;
- };
-
- /**
- * An object that contains width and height values of the `Component`s
- * computed style. Uses `window.getComputedStyle`.
- *
- * @typedef {Object} Component~DimensionObject
- *
- * @property {number} width
- * The width of the `Component`s computed style.
- *
- * @property {number} height
- * The height of the `Component`s computed style.
- */
-
- /**
- * Get an object that contains width and height values of the `Component`s
- * computed style.
- *
- * @return {Component~DimensionObject}
- * The dimensions of the components element
- */
-
-
- Component.prototype.currentDimensions = function currentDimensions() {
- return {
- width: this.currentDimension('width'),
- height: this.currentDimension('height')
- };
- };
-
- /**
- * Get the width of the `Component`s computed style. Uses `window.getComputedStyle`.
- *
- * @return {number} width
- * The width of the `Component`s computed style.
- */
-
-
- Component.prototype.currentWidth = function currentWidth() {
- return this.currentDimension('width');
- };
-
- /**
- * Get the height of the `Component`s computed style. Uses `window.getComputedStyle`.
- *
- * @return {number} height
- * The height of the `Component`s computed style.
- */
-
-
- Component.prototype.currentHeight = function currentHeight() {
- return this.currentDimension('height');
- };
-
- /**
- * Set the focus to this component
- */
-
-
- Component.prototype.focus = function focus() {
- this.el_.focus();
- };
-
- /**
- * Remove the focus from this component
- */
-
-
- Component.prototype.blur = function blur() {
- this.el_.blur();
- };
-
- /**
- * Emit a 'tap' events when touch event support gets detected. This gets used to
- * support toggling the controls through a tap on the video. They get enabled
- * because every sub-component would have extra overhead otherwise.
- *
- * @private
- * @fires Component#tap
- * @listens Component#touchstart
- * @listens Component#touchmove
- * @listens Component#touchleave
- * @listens Component#touchcancel
- * @listens Component#touchend
- */
-
-
- Component.prototype.emitTapEvents = function emitTapEvents() {
- // Track the start time so we can determine how long the touch lasted
- var touchStart = 0;
- var firstTouch = null;
-
- // Maximum movement allowed during a touch event to still be considered a tap
- // Other popular libs use anywhere from 2 (hammer.js) to 15,
- // so 10 seems like a nice, round number.
- var tapMovementThreshold = 10;
-
- // The maximum length a touch can be while still being considered a tap
- var touchTimeThreshold = 200;
-
- var couldBeTap = void 0;
-
- this.on('touchstart', function (event) {
- // If more than one finger, don't consider treating this as a click
- if (event.touches.length === 1) {
- // Copy pageX/pageY from the object
- firstTouch = {
- pageX: event.touches[0].pageX,
- pageY: event.touches[0].pageY
- };
- // Record start time so we can detect a tap vs. "touch and hold"
- touchStart = new Date().getTime();
- // Reset couldBeTap tracking
- couldBeTap = true;
- }
- });
-
- this.on('touchmove', function (event) {
- // If more than one finger, don't consider treating this as a click
- if (event.touches.length > 1) {
- couldBeTap = false;
- } else if (firstTouch) {
- // Some devices will throw touchmoves for all but the slightest of taps.
- // So, if we moved only a small distance, this could still be a tap
- var xdiff = event.touches[0].pageX - firstTouch.pageX;
- var ydiff = event.touches[0].pageY - firstTouch.pageY;
- var touchDistance = Math.sqrt(xdiff * xdiff + ydiff * ydiff);
-
- if (touchDistance > tapMovementThreshold) {
- couldBeTap = false;
- }
- }
- });
-
- var noTap = function noTap() {
- couldBeTap = false;
- };
-
- // TODO: Listen to the original target. http://youtu.be/DujfpXOKUp8?t=13m8s
- this.on('touchleave', noTap);
- this.on('touchcancel', noTap);
-
- // When the touch ends, measure how long it took and trigger the appropriate
- // event
- this.on('touchend', function (event) {
- firstTouch = null;
- // Proceed only if the touchmove/leave/cancel event didn't happen
- if (couldBeTap === true) {
- // Measure how long the touch lasted
- var touchTime = new Date().getTime() - touchStart;
-
- // Make sure the touch was less than the threshold to be considered a tap
- if (touchTime < touchTimeThreshold) {
- // Don't let browser turn this into a click
- event.preventDefault();
- /**
- * Triggered when a `Component` is tapped.
- *
- * @event Component#tap
- * @type {EventTarget~Event}
- */
- this.trigger('tap');
- // It may be good to copy the touchend event object and change the
- // type to tap, if the other event properties aren't exact after
- // Events.fixEvent runs (e.g. event.target)
- }
- }
- });
- };
-
- /**
- * This function reports user activity whenever touch events happen. This can get
- * turned off by any sub-components that wants touch events to act another way.
- *
- * Report user touch activity when touch events occur. User activity gets used to
- * determine when controls should show/hide. It is simple when it comes to mouse
- * events, because any mouse event should show the controls. So we capture mouse
- * events that bubble up to the player and report activity when that happens.
- * With touch events it isn't as easy as `touchstart` and `touchend` toggle player
- * controls. So touch events can't help us at the player level either.
- *
- * User activity gets checked asynchronously. So what could happen is a tap event
- * on the video turns the controls off. Then the `touchend` event bubbles up to
- * the player. Which, if it reported user activity, would turn the controls right
- * back on. We also don't want to completely block touch events from bubbling up.
- * Furthermore a `touchmove` event and anything other than a tap, should not turn
- * controls back on.
- *
- * @listens Component#touchstart
- * @listens Component#touchmove
- * @listens Component#touchend
- * @listens Component#touchcancel
- */
-
-
- Component.prototype.enableTouchActivity = function enableTouchActivity() {
- // Don't continue if the root player doesn't support reporting user activity
- if (!this.player() || !this.player().reportUserActivity) {
- return;
- }
-
- // listener for reporting that the user is active
- var report = bind(this.player(), this.player().reportUserActivity);
-
- var touchHolding = void 0;
-
- this.on('touchstart', function () {
- report();
- // For as long as the they are touching the device or have their mouse down,
- // we consider them active even if they're not moving their finger or mouse.
- // So we want to continue to update that they are active
- this.clearInterval(touchHolding);
- // report at the same interval as activityCheck
- touchHolding = this.setInterval(report, 250);
- });
-
- var touchEnd = function touchEnd(event) {
- report();
- // stop the interval that maintains activity if the touch is holding
- this.clearInterval(touchHolding);
- };
-
- this.on('touchmove', report);
- this.on('touchend', touchEnd);
- this.on('touchcancel', touchEnd);
- };
-
- /**
- * A callback that has no parameters and is bound into `Component`s context.
- *
- * @callback Component~GenericCallback
- * @this Component
- */
-
- /**
- * Creates a function that runs after an `x` millisecond timeout. This function is a
- * wrapper around `window.setTimeout`. There are a few reasons to use this one
- * instead though:
- * 1. It gets cleared via {@link Component#clearTimeout} when
- * {@link Component#dispose} gets called.
- * 2. The function callback will gets turned into a {@link Component~GenericCallback}
- *
- * > Note: You can use `window.clearTimeout` on the id returned by this function. This
- * will cause its dispose listener not to get cleaned up! Please use
- * {@link Component#clearTimeout} or {@link Component#dispose}.
- *
- * @param {Component~GenericCallback} fn
- * The function that will be run after `timeout`.
- *
- * @param {number} timeout
- * Timeout in milliseconds to delay before executing the specified function.
- *
- * @return {number}
- * Returns a timeout ID that gets used to identify the timeout. It can also
- * get used in {@link Component#clearTimeout} to clear the timeout that
- * was set.
- *
- * @listens Component#dispose
- * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout}
- */
-
-
- Component.prototype.setTimeout = function setTimeout(fn, timeout) {
- var _this2 = this;
-
- fn = bind(this, fn);
-
- var timeoutId = window_1.setTimeout(fn, timeout);
- var disposeFn = function disposeFn() {
- return _this2.clearTimeout(timeoutId);
- };
-
- disposeFn.guid = 'vjs-timeout-' + timeoutId;
-
- this.on('dispose', disposeFn);
-
- return timeoutId;
- };
-
- /**
- * Clears a timeout that gets created via `window.setTimeout` or
- * {@link Component#setTimeout}. If you set a timeout via {@link Component#setTimeout}
- * use this function instead of `window.clearTimout`. If you don't your dispose
- * listener will not get cleaned up until {@link Component#dispose}!
- *
- * @param {number} timeoutId
- * The id of the timeout to clear. The return value of
- * {@link Component#setTimeout} or `window.setTimeout`.
- *
- * @return {number}
- * Returns the timeout id that was cleared.
- *
- * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/clearTimeout}
- */
-
-
- Component.prototype.clearTimeout = function clearTimeout(timeoutId) {
- window_1.clearTimeout(timeoutId);
-
- var disposeFn = function disposeFn() {};
-
- disposeFn.guid = 'vjs-timeout-' + timeoutId;
-
- this.off('dispose', disposeFn);
-
- return timeoutId;
- };
-
- /**
- * Creates a function that gets run every `x` milliseconds. This function is a wrapper
- * around `window.setInterval`. There are a few reasons to use this one instead though.
- * 1. It gets cleared via {@link Component#clearInterval} when
- * {@link Component#dispose} gets called.
- * 2. The function callback will be a {@link Component~GenericCallback}
- *
- * @param {Component~GenericCallback} fn
- * The function to run every `x` seconds.
- *
- * @param {number} interval
- * Execute the specified function every `x` milliseconds.
- *
- * @return {number}
- * Returns an id that can be used to identify the interval. It can also be be used in
- * {@link Component#clearInterval} to clear the interval.
- *
- * @listens Component#dispose
- * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setInterval}
- */
-
-
- Component.prototype.setInterval = function setInterval(fn, interval) {
- var _this3 = this;
-
- fn = bind(this, fn);
-
- var intervalId = window_1.setInterval(fn, interval);
-
- var disposeFn = function disposeFn() {
- return _this3.clearInterval(intervalId);
- };
-
- disposeFn.guid = 'vjs-interval-' + intervalId;
-
- this.on('dispose', disposeFn);
-
- return intervalId;
- };
-
- /**
- * Clears an interval that gets created via `window.setInterval` or
- * {@link Component#setInterval}. If you set an inteval via {@link Component#setInterval}
- * use this function instead of `window.clearInterval`. If you don't your dispose
- * listener will not get cleaned up until {@link Component#dispose}!
- *
- * @param {number} intervalId
- * The id of the interval to clear. The return value of
- * {@link Component#setInterval} or `window.setInterval`.
- *
- * @return {number}
- * Returns the interval id that was cleared.
- *
- * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/clearInterval}
- */
-
-
- Component.prototype.clearInterval = function clearInterval(intervalId) {
- window_1.clearInterval(intervalId);
-
- var disposeFn = function disposeFn() {};
-
- disposeFn.guid = 'vjs-interval-' + intervalId;
-
- this.off('dispose', disposeFn);
-
- return intervalId;
- };
-
- /**
- * Queues up a callback to be passed to requestAnimationFrame (rAF), but
- * with a few extra bonuses:
- *
- * - Supports browsers that do not support rAF by falling back to
- * {@link Component#setTimeout}.
- *
- * - 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}
- */
-
-
- Component.prototype.requestAnimationFrame = function requestAnimationFrame(fn) {
- var _this4 = this;
-
- if (this.supportsRaf_) {
- fn = bind(this, fn);
-
- var id = window_1.requestAnimationFrame(fn);
- var disposeFn = function disposeFn() {
- return _this4.cancelAnimationFrame(id);
- };
-
- disposeFn.guid = 'vjs-raf-' + id;
- this.on('dispose', disposeFn);
-
- return id;
- }
-
- // Fall back to using a timer.
- return this.setTimeout(fn, 1000 / 60);
- };
-
- /**
- * Cancels a queued callback passed to {@link Component#requestAnimationFrame}
- * (rAF).
- *
- * 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}!
- *
- * @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}
- */
-
-
- Component.prototype.cancelAnimationFrame = function cancelAnimationFrame(id) {
- if (this.supportsRaf_) {
- window_1.cancelAnimationFrame(id);
-
- var disposeFn = function disposeFn() {};
-
- disposeFn.guid = 'vjs-raf-' + id;
-
- this.off('dispose', disposeFn);
-
- return id;
- }
-
- // Fall back to using a timer.
- return this.clearTimeout(id);
- };
-
- /**
- * 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.
- */
-
-
- 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 Tech = Component.getComponent('Tech');
-
- // 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);
-
- if (isTech || !isComp) {
- var reason = void 0;
-
- if (isTech) {
- reason = 'techs must be registered using Tech.registerTech()';
- } else {
- reason = 'must be a Component subclass';
- }
-
- throw new Error('Illegal component, "' + name + '"; ' + reason + '.');
- }
-
- name = toTitleCase(name);
-
- if (!Component.components_) {
- Component.components_ = {};
- }
-
- var Player = Component.getComponent('Player');
-
- if (name === 'Player' && Player && Player.players) {
- var players = Player.players;
- var playerNames = Object.keys(players);
-
- // 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.');
- }
- }
-
- Component.components_[name] = ComponentToRegister;
-
- return ComponentToRegister;
- };
-
- /**
- * Get a `Component` based on the name it was registered with.
- *
- * @param {string} name
- * The Name of the component to get.
- *
- * @return {Component}
- * The `Component` that got registered under the given name.
- *
- * @deprecated In `videojs` 6 this will not return `Component`s that were not
- * registered using {@link Component.registerComponent}. Currently we
- * check the global `videojs` object for a `Component` name and
- * return that if it exists.
- */
-
-
- Component.getComponent = function getComponent(name) {
- if (!name) {
- return;
- }
-
- name = toTitleCase(name);
-
- if (Component.components_ && Component.components_[name]) {
- return Component.components_[name];
- }
- };
-
- return Component;
- }();
-
- /**
- * Whether or not this component supports `requestAnimationFrame`.
- *
- * This is exposed primarily for testing purposes.
- *
- * @private
- * @type {Boolean}
- */
-
-
- Component.prototype.supportsRaf_ = typeof window_1.requestAnimationFrame === 'function' && typeof window_1.cancelAnimationFrame === 'function';
-
- Component.registerComponent('Component', Component);
-
- /**
- * @file time-ranges.js
- * @module time-ranges
- */
-
- /**
- * Returns the time for the specified index at the start or end
- * of a TimeRange object.
- *
- * @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.
- */
-
- /**
- * 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
- */
-
- /**
- * 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 + ').');
- }
- }
-
- /**
- * 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];
- }
-
- /**
- * 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)
- };
- }
-
- /**
- * 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]]);
- }
-
- /**
- * @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;
- }
-
- if (!buffered || !buffered.length) {
- buffered = createTimeRanges(0, 0);
- }
-
- 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;
- }
-
- bufferedDuration += end - start;
- }
-
- return bufferedDuration / duration;
- }
-
- /**
- * @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']];
-
- var specApi = apiMap[0];
- var browserApi = void 0;
-
-// 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;
- }
- }
-
-// 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];
- }
- }
-
- /**
- * @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) {
-
- // Allow redundant calls to this constructor to avoid having `instanceof`
- // checks peppered around the code.
- if (value instanceof MediaError) {
- return value;
- }
-
- 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)) {
-
- // 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;
- }
-
- assign(this, value);
- }
-
- if (!this.message) {
- this.message = MediaError.defaultMessages[this.code] || '';
- }
- }
-
- /**
- * The error code that refers two one of the defined `MediaError` types
- *
- * @type {Number}
- */
- MediaError.prototype.code = 0;
-
- /**
- * 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;
-
- /**
- * Errors indexed by the W3C standard. The order **CANNOT CHANGE**! See the
- * specification listed under {@link MediaError} for more information.
- *
- * @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
- */
- MediaError.errorTypes = ['MEDIA_ERR_CUSTOM', 'MEDIA_ERR_ABORTED', 'MEDIA_ERR_NETWORK', 'MEDIA_ERR_DECODE', 'MEDIA_ERR_SRC_NOT_SUPPORTED', 'MEDIA_ERR_ENCRYPTED'];
-
- /**
- * 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 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;
- }
-
- var tuple = SafeParseTuple;
-
- function SafeParseTuple(obj, reviver) {
- var json;
- var error = null;
-
- try {
- json = JSON.parse(obj, reviver);
- } catch (err) {
- error = err;
- }
-
- return [error, json]
- }
-
- /**
- * Returns whether an object is `Promise`-like (i.e. has a `then` method).
- *
- * @param {Object} value
- * An object that may or may not be `Promise`-like.
- *
- * @return {Boolean}
- * Whether or not the object is `Promise`-like.
- */
- function isPromise(value) {
- return value !== undefined && typeof value.then === 'function';
- }
-
- /**
- * Silence a Promise-like object.
- *
- * This is useful for avoiding non-harmful, but potentially confusing "uncaught
- * play promise" rejection error messages.
- *
- * @param {Object} value
- * An object that may or may not be `Promise`-like.
- */
- function silencePromise(value) {
- if (isPromise(value)) {
- value.then(null, function (e) {});
- }
- }
-
- /**
- * @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
- */
-
- /**
- * 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) {
-
- if (track[prop]) {
- acc[prop] = track[prop];
- }
-
- 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
- };
- })
- });
-
- return ret;
- };
-
- /**
- * 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 trackEls = tech.$$('track');
-
- 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);
-
- if (trackEl.src) {
- json.src = trackEl.src;
- }
- return json;
- });
-
- return tracks.concat(Array.prototype.filter.call(tech.textTracks(), function (track) {
- return trackObjs.indexOf(track) === -1;
- }).map(trackToJson_));
- };
-
- /**
- * 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;
-
- if (!track.src && track.cues) {
- track.cues.forEach(function (cue) {
- return addedTrack.addCue(cue);
- });
- }
- });
-
- return tech.textTracks();
- };
-
- var textTrackConverter = { textTracksToJson: textTracksToJson, jsonToTextTracks: jsonToTextTracks, trackToJson_: trackToJson_ };
-
- /**
- * @file modal-dialog.js
- */
- var MODAL_CLASS_NAME = 'vjs-modal-dialog';
- var ESC = 27;
-
- /**
- * 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 ModalDialog = function (_Component) {
- inherits(ModalDialog, _Component);
-
- /**
- * 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 ModalDialog(player, options) {
- classCallCheck(this, ModalDialog);
-
- var _this = possibleConstructorReturn(this, _Component.call(this, player, options));
-
- _this.opened_ = _this.hasBeenOpened_ = _this.hasBeenFilled_ = false;
-
- _this.closeable(!_this.options_.uncloseable);
- _this.content(_this.options_.content);
-
- // 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'
- });
-
- _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 `ModalDialog`'s DOM element
- *
- * @return {Element}
- * The DOM element that gets created.
- */
-
-
- ModalDialog.prototype.createEl = function createEl$$1() {
- return _Component.prototype.createEl.call(this, 'div', {
- className: this.buildCSSClass(),
- tabIndex: -1
- }, {
- 'aria-describedby': this.id() + '_description',
- 'aria-hidden': 'true',
- 'aria-label': this.label(),
- 'role': 'dialog'
- });
- };
-
- ModalDialog.prototype.dispose = function dispose() {
- this.contentEl_ = null;
- this.descEl_ = null;
- this.previouslyActiveEl_ = null;
-
- _Component.prototype.dispose.call(this);
- };
-
- /**
- * Builds the default DOM `className`.
- *
- * @return {string}
- * The DOM `className` for this object.
- */
-
-
- ModalDialog.prototype.buildCSSClass = function buildCSSClass() {
- return MODAL_CLASS_NAME + ' vjs-hidden ' + _Component.prototype.buildCSSClass.call(this);
- };
-
- /**
- * Handles `keydown` events on the document, looking for ESC, which closes
- * the modal.
- *
- * @param {EventTarget~Event} e
- * The keypress that triggered this event.
- *
- * @listens keydown
- */
-
-
- ModalDialog.prototype.handleKeyPress = function handleKeyPress(e) {
- if (e.which === ESC && this.closeable()) {
- this.close();
- }
- };
-
- /**
- * Returns the label string for this modal. Primarily used for accessibility.
- *
- * @return {string}
- * the localized or raw label of this modal.
- */
-
-
- ModalDialog.prototype.label = function label() {
- return this.localize(this.options_.label || 'Modal Window');
- };
-
- /**
- * Returns the description string for this modal. Primarily used for
- * accessibility.
- *
- * @return {string}
- * The localized or raw description of this modal.
- */
-
-
- ModalDialog.prototype.description = function description() {
- var desc = this.options_.description || this.localize('This is a modal window.');
-
- // 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 desc;
- };
-
- /**
- * Opens the modal.
- *
- * @fires ModalDialog#beforemodalopen
- * @fires ModalDialog#modalopen
- */
-
-
- ModalDialog.prototype.open = function open() {
- if (!this.opened_) {
- var player = this.player();
-
- /**
- * Fired just before a `ModalDialog` is opened.
- *
- * @event ModalDialog#beforemodalopen
- * @type {EventTarget~Event}
- */
- this.trigger('beforemodalopen');
- this.opened_ = true;
-
- // Fill content if the modal has never opened before and
- // never been filled.
- if (this.options_.fillAlways || !this.hasBeenOpened_ && !this.hasBeenFilled_) {
- this.fill();
- }
-
- // If the player was playing, pause it and take note of its previously
- // playing state.
- this.wasPlaying_ = !player.paused();
-
- if (this.options_.pauseOnOpen && this.wasPlaying_) {
- player.pause();
- }
-
- if (this.closeable()) {
- this.on(this.el_.ownerDocument, 'keydown', bind(this, this.handleKeyPress));
- }
-
- // Hide controls and note if they were enabled.
- this.hadControls_ = player.controls();
- player.controls(false);
-
- this.show();
- this.conditionalFocus_();
- this.el().setAttribute('aria-hidden', 'false');
-
- /**
- * Fired just after a `ModalDialog` is opened.
- *
- * @event ModalDialog#modalopen
- * @type {EventTarget~Event}
- */
- this.trigger('modalopen');
- this.hasBeenOpened_ = true;
- }
- };
-
- /**
- * 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
- */
-
-
- ModalDialog.prototype.opened = function opened(value) {
- if (typeof value === 'boolean') {
- this[value ? 'open' : 'close']();
- }
- return this.opened_;
- };
-
- /**
- * Closes the modal, does nothing if the `ModalDialog` is
- * not open.
- *
- * @fires ModalDialog#beforemodalclose
- * @fires ModalDialog#modalclose
- */
-
-
- ModalDialog.prototype.close = function close() {
- if (!this.opened_) {
- return;
- }
- var player = this.player();
-
- /**
- * 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.closeable()) {
- this.off(this.el_.ownerDocument, 'keydown', bind(this, this.handleKeyPress));
- }
-
- if (this.hadControls_) {
- 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_();
-
- if (this.options_.temporary) {
- this.dispose();
- }
- };
-
- /**
- * Check to see if the `ModalDialog` is closeable via the UI.
- *
- * @param {boolean} [value]
- * If given as a boolean, it will set the `closeable` option.
- *
- * @return {boolean}
- * Returns the final value of the closable option.
- */
-
-
- ModalDialog.prototype.closeable = function closeable(value) {
- if (typeof value === 'boolean') {
- var closeable = this.closeable_ = !!value;
- var close = this.getChild('closeButton');
-
- // If this is being made closeable and has no close button, add one.
- if (closeable && !close) {
-
- // The close button should be a child of the modal - not its
- // content element, so temporarily change the content element.
- var temp = this.contentEl_;
-
- this.contentEl_ = this.el_;
- close = this.addChild('closeButton', { controlText: 'Close Modal Dialog' });
- this.contentEl_ = temp;
- this.on(close, 'close', this.close);
- }
-
- // 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_;
- };
-
- /**
- * Fill the modal's content element with the modal's "content" option.
- * The content element will be emptied before this change takes place.
- */
-
-
- ModalDialog.prototype.fill = function fill() {
- this.fillWith(this.content());
- };
-
- /**
- * 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.
- */
-
-
- ModalDialog.prototype.fillWith = function fillWith(content) {
- var contentEl = this.contentEl();
- var parentEl = contentEl.parentNode;
- var nextSiblingEl = contentEl.nextSibling;
-
- /**
- * 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');
-
- // Re-inject the re-filled content element.
- if (nextSiblingEl) {
- parentEl.insertBefore(contentEl, nextSiblingEl);
- } else {
- parentEl.appendChild(contentEl);
- }
-
- // make sure that the close button is last in the dialog DOM
- var closeButton = this.getChild('closeButton');
-
- if (closeButton) {
- parentEl.appendChild(closeButton.el_);
- }
- };
-
- /**
- * Empties the content element. This happens anytime the modal is filled.
- *
- * @fires ModalDialog#beforemodalempty
- * @fires ModalDialog#modalempty
- */
-
-
- ModalDialog.prototype.empty = function empty() {
- /**
- * Fired just before a `ModalDialog` is emptied.
- *
- * @event ModalDialog#beforemodalempty
- * @type {EventTarget~Event}
- */
- this.trigger('beforemodalempty');
- emptyEl(this.contentEl());
-
- /**
- * Fired just after a `ModalDialog` is emptied.
- *
- * @event ModalDialog#modalempty
- * @type {EventTarget~Event}
- */
- this.trigger('modalempty');
- };
-
- /**
- * Gets or sets the modal content, which gets normalized before being
- * rendered into the DOM.
- *
- * This does not update the DOM or fill the modal, but it is called during
- * that process.
- *
- * @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
- */
-
-
- ModalDialog.prototype.content = function content(value) {
- if (typeof value !== 'undefined') {
- this.content_ = value;
- }
- return this.content_;
- };
-
- /**
- * conditionally focus the modal dialog if focus was previously on the player.
- *
- * @private
- */
-
-
- ModalDialog.prototype.conditionalFocus_ = function conditionalFocus_() {
- var activeEl = document_1.activeElement;
- var playerEl = this.player_.el_;
-
- this.previouslyActiveEl_ = null;
-
- if (playerEl.contains(activeEl) || playerEl === activeEl) {
- this.previouslyActiveEl_ = activeEl;
-
- this.focus();
-
- this.on(document_1, 'keydown', this.handleKeyDown);
- }
- };
-
- /**
- * conditionally blur the element and refocus the last focused element
- *
- * @private
- */
-
-
- ModalDialog.prototype.conditionalBlur_ = function conditionalBlur_() {
- if (this.previouslyActiveEl_) {
- this.previouslyActiveEl_.focus();
- this.previouslyActiveEl_ = null;
- }
-
- this.off(document_1, 'keydown', this.handleKeyDown);
- };
-
- /**
- * Keydown handler. Attached when modal is focused.
- *
- * @listens keydown
- */
-
-
- ModalDialog.prototype.handleKeyDown = function handleKeyDown(event) {
- // exit early if it isn't a tab key
- if (event.which !== 9) {
- return;
- }
-
- 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;
- }
- }
-
- if (document_1.activeElement === this.el_) {
- focusIndex = 0;
- }
-
- 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();
- }
- };
-
- /**
- * get all focusable elements
- *
- * @private
- */
-
-
- ModalDialog.prototype.focusableEls_ = function focusableEls_() {
- var allChildren = this.el_.querySelectorAll('*');
-
- 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 ModalDialog;
- }(Component);
-
- /**
- * Default options for `ModalDialog` default options.
- *
- * @type {Object}
- * @private
- */
-
-
- ModalDialog.prototype.options_ = {
- pauseOnOpen: true,
- temporary: true
- };
-
- Component.registerComponent('ModalDialog', ModalDialog);
-
- /**
- * @file track-list.js
- */
- /**
- * Common functionaliy between {@link TextTrackList}, {@link AudioTrackList}, and
- * {@link VideoTrackList}
- *
- * @extends EventTarget
- */
-
- var TrackList = function (_EventTarget) {
- inherits(TrackList, _EventTarget);
-
- /**
- * Create an instance of this class
- *
- * @param {Track[]} tracks
- * A list of tracks to initialize the list with.
- *
- * @param {Object} [list]
- * The child object with inheritance done manually for ie8.
- *
- * @abstract
- */
- function TrackList() {
- var tracks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
-
- var _ret;
-
- var list = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
- classCallCheck(this, TrackList);
-
- var _this = possibleConstructorReturn(this, _EventTarget.call(this));
-
- if (!list) {
- list = _this; // eslint-disable-line
- if (IS_IE8) {
- list = document_1.createElement('custom');
- for (var prop in TrackList.prototype) {
- if (prop !== 'constructor') {
- list[prop] = TrackList.prototype[prop];
- }
- }
- }
- }
-
- list.tracks_ = [];
-
- /**
- * @memberof TrackList
- * @member {number} length
- * The current number of `Track`s in the this Trackist.
- * @instance
- */
- Object.defineProperty(list, 'length', {
- get: function get$$1() {
- return this.tracks_.length;
- }
- });
-
- for (var i = 0; i < tracks.length; i++) {
- list.addTrack(tracks[i]);
- }
-
- // must return the object, as for ie8 it will not be this
- // but a reference to a document object
- return _ret = list, possibleConstructorReturn(_this, _ret);
- }
-
- /**
- * Add a {@link Track} to the `TrackList`
- *
- * @param {Track} track
- * The audio, video, or text track to add to the list.
- *
- * @fires TrackList#addtrack
- */
-
-
- TrackList.prototype.addTrack = function addTrack(track) {
- var index = this.tracks_.length;
-
- if (!('' + index in this)) {
- Object.defineProperty(this, index, {
- get: function get$$1() {
- return this.tracks_[index];
- }
- });
- }
-
- // Do not add duplicate tracks
- if (this.tracks_.indexOf(track) === -1) {
- this.tracks_.push(track);
- /**
- * Triggered when a track is added to a track list.
- *
- * @event TrackList#addtrack
- * @type {EventTarget~Event}
- * @property {Track} track
- * A reference to track that was added.
- */
- this.trigger({
- track: track,
- type: 'addtrack'
- });
- }
- };
-
- /**
- * Remove a {@link Track} from the `TrackList`
- *
- * @param {Track} rtrack
- * The audio, video, or text track to remove from the list.
- *
- * @fires TrackList#removetrack
- */
-
-
- TrackList.prototype.removeTrack = function removeTrack(rtrack) {
- var track = void 0;
-
- for (var i = 0, l = this.length; i < l; i++) {
- if (this[i] === rtrack) {
- track = this[i];
- if (track.off) {
- track.off();
- }
-
- this.tracks_.splice(i, 1);
-
- break;
- }
- }
-
- if (!track) {
- return;
- }
-
- /**
- * Triggered when a track is removed from track list.
- *
- * @event TrackList#removetrack
- * @type {EventTarget~Event}
- * @property {Track} track
- * A reference to track that was removed.
- */
- this.trigger({
- track: track,
- type: 'removetrack'
- });
- };
-
- /**
- * Get a Track from the TrackList by a tracks id
- *
- * @param {String} id - the id of the track to get
- * @method getTrackById
- * @return {Track}
- * @private
- */
-
-
- TrackList.prototype.getTrackById = function getTrackById(id) {
- var result = null;
-
- for (var i = 0, l = this.length; i < l; i++) {
- var track = this[i];
-
- if (track.id === id) {
- result = track;
- break;
- }
- }
-
- return result;
- };
-
- return TrackList;
- }(EventTarget);
-
- /**
- * Triggered when a different track is selected/enabled.
- *
- * @event TrackList#change
- * @type {EventTarget~Event}
- */
-
- /**
- * Events that can be called with on + eventName. See {@link EventHandler}.
- *
- * @property {Object} TrackList#allowedEvents_
- * @private
- */
-
-
- TrackList.prototype.allowedEvents_ = {
- change: 'change',
- addtrack: 'addtrack',
- removetrack: 'removetrack'
- };
-
-// emulate attribute EventHandler support to allow for feature detection
- for (var event in TrackList.prototype.allowedEvents_) {
- TrackList.prototype['on' + event] = null;
- }
-
- /**
- * @file audio-track-list.js
- */
- /**
- * Anywhere we call this function we diverge from the spec
- * as we only support one enabled audiotrack at a time
- *
- * @param {AudioTrackList} list
- * list to work on
- *
- * @param {AudioTrack} track
- * The track to skip
- *
- * @private
- */
- var disableOthers = function disableOthers(list, track) {
- for (var i = 0; i < list.length; i++) {
- if (!Object.keys(list[i]).length || track.id === list[i].id) {
- continue;
- }
- // another audio track is enabled, disable it
- list[i].enabled = false;
- }
- };
-
- /**
- * The current list of {@link AudioTrack} for a media file.
- *
- * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#audiotracklist}
- * @extends TrackList
- */
-
- var AudioTrackList = function (_TrackList) {
- inherits(AudioTrackList, _TrackList);
-
- /**
- * Create an instance of this class.
- *
- * @param {AudioTrack[]} [tracks=[]]
- * A list of `AudioTrack` to instantiate the list with.
- */
- function AudioTrackList() {
- var _this, _ret;
-
- var tracks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
- classCallCheck(this, AudioTrackList);
-
- var list = void 0;
-
- // make sure only 1 track is enabled
- // sorted from last index to first index
- for (var i = tracks.length - 1; i >= 0; i--) {
- if (tracks[i].enabled) {
- disableOthers(tracks, tracks[i]);
- break;
- }
- }
-
- // IE8 forces us to implement inheritance ourselves
- // as it does not support Object.defineProperty properly
- if (IS_IE8) {
- list = document_1.createElement('custom');
- for (var prop in TrackList.prototype) {
- if (prop !== 'constructor') {
- list[prop] = TrackList.prototype[prop];
- }
- }
- for (var _prop in AudioTrackList.prototype) {
- if (_prop !== 'constructor') {
- list[_prop] = AudioTrackList.prototype[_prop];
- }
- }
- }
-
- list = (_this = possibleConstructorReturn(this, _TrackList.call(this, tracks, list)), _this);
- list.changing_ = false;
-
- return _ret = list, possibleConstructorReturn(_this, _ret);
- }
-
- /**
- * Add an {@link AudioTrack} to the `AudioTrackList`.
- *
- * @param {AudioTrack} track
- * The AudioTrack to add to the list
- *
- * @fires TrackList#addtrack
- */
-
-
- AudioTrackList.prototype.addTrack = function addTrack(track) {
- var _this2 = this;
-
- if (track.enabled) {
- disableOthers(this, track);
- }
-
- _TrackList.prototype.addTrack.call(this, track);
- // native tracks don't have this
- if (!track.addEventListener) {
- return;
- }
-
- /**
- * @listens AudioTrack#enabledchange
- * @fires TrackList#change
- */
- track.addEventListener('enabledchange', function () {
- // when we are disabling other tracks (since we don't support
- // more than one track at a time) we will set changing_
- // to true so that we don't trigger additional change events
- if (_this2.changing_) {
- return;
- }
- _this2.changing_ = true;
- disableOthers(_this2, track);
- _this2.changing_ = false;
- _this2.trigger('change');
- });
- };
-
- return AudioTrackList;
- }(TrackList);
-
- /**
- * @file video-track-list.js
- */
- /**
- * Un-select all other {@link VideoTrack}s that are selected.
- *
- * @param {VideoTrackList} list
- * list to work on
- *
- * @param {VideoTrack} track
- * The track to skip
- *
- * @private
- */
- var disableOthers$1 = function disableOthers(list, track) {
- for (var i = 0; i < list.length; i++) {
- if (!Object.keys(list[i]).length || track.id === list[i].id) {
- continue;
- }
- // another video track is enabled, disable it
- list[i].selected = false;
- }
- };
-
- /**
- * The current list of {@link VideoTrack} for a video.
- *
- * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#videotracklist}
- * @extends TrackList
- */
-
- var VideoTrackList = function (_TrackList) {
- inherits(VideoTrackList, _TrackList);
-
- /**
- * Create an instance of this class.
- *
- * @param {VideoTrack[]} [tracks=[]]
- * A list of `VideoTrack` to instantiate the list with.
- */
- function VideoTrackList() {
- var _this, _ret;
-
- var tracks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
- classCallCheck(this, VideoTrackList);
-
- var list = void 0;
-
- // make sure only 1 track is enabled
- // sorted from last index to first index
- for (var i = tracks.length - 1; i >= 0; i--) {
- if (tracks[i].selected) {
- disableOthers$1(tracks, tracks[i]);
- break;
- }
- }
-
- // IE8 forces us to implement inheritance ourselves
- // as it does not support Object.defineProperty properly
- if (IS_IE8) {
- list = document_1.createElement('custom');
- for (var prop in TrackList.prototype) {
- if (prop !== 'constructor') {
- list[prop] = TrackList.prototype[prop];
- }
- }
- for (var _prop in VideoTrackList.prototype) {
- if (_prop !== 'constructor') {
- list[_prop] = VideoTrackList.prototype[_prop];
- }
- }
- }
-
- list = (_this = possibleConstructorReturn(this, _TrackList.call(this, tracks, list)), _this);
- list.changing_ = false;
-
- /**
- * @member {number} VideoTrackList#selectedIndex
- * The current index of the selected {@link VideoTrack`}.
- */
- Object.defineProperty(list, 'selectedIndex', {
- get: function get$$1() {
- for (var _i = 0; _i < this.length; _i++) {
- if (this[_i].selected) {
- return _i;
- }
- }
- return -1;
- },
- set: function set$$1() {}
- });
-
- return _ret = list, possibleConstructorReturn(_this, _ret);
- }
-
- /**
- * Add a {@link VideoTrack} to the `VideoTrackList`.
- *
- * @param {VideoTrack} track
- * The VideoTrack to add to the list
- *
- * @fires TrackList#addtrack
- */
-
-
- VideoTrackList.prototype.addTrack = function addTrack(track) {
- var _this2 = this;
-
- if (track.selected) {
- disableOthers$1(this, track);
- }
-
- _TrackList.prototype.addTrack.call(this, track);
- // native tracks don't have this
- if (!track.addEventListener) {
- return;
- }
-
- /**
- * @listens VideoTrack#selectedchange
- * @fires TrackList#change
- */
- track.addEventListener('selectedchange', function () {
- if (_this2.changing_) {
- return;
- }
- _this2.changing_ = true;
- disableOthers$1(_this2, track);
- _this2.changing_ = false;
- _this2.trigger('change');
- });
- };
-
- return VideoTrackList;
- }(TrackList);
-
- /**
- * @file text-track-list.js
- */
- /**
- * The current list of {@link TextTrack} for a media file.
- *
- * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#texttracklist}
- * @extends TrackList
- */
-
- var TextTrackList = function (_TrackList) {
- inherits(TextTrackList, _TrackList);
-
- /**
- * Create an instance of this class.
- *
- * @param {TextTrack[]} [tracks=[]]
- * A list of `TextTrack` to instantiate the list with.
- */
- function TextTrackList() {
- var _this, _ret;
-
- var tracks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
- classCallCheck(this, TextTrackList);
-
- var list = void 0;
-
- // IE8 forces us to implement inheritance ourselves
- // as it does not support Object.defineProperty properly
- if (IS_IE8) {
- list = document_1.createElement('custom');
- for (var prop in TrackList.prototype) {
- if (prop !== 'constructor') {
- list[prop] = TrackList.prototype[prop];
- }
- }
- for (var _prop in TextTrackList.prototype) {
- if (_prop !== 'constructor') {
- list[_prop] = TextTrackList.prototype[_prop];
- }
- }
- }
-
- list = (_this = possibleConstructorReturn(this, _TrackList.call(this, tracks, list)), _this);
- return _ret = list, possibleConstructorReturn(_this, _ret);
- }
-
- /**
- * Add a {@link TextTrack} to the `TextTrackList`
- *
- * @param {TextTrack} track
- * The text track to add to the list.
- *
- * @fires TrackList#addtrack
- */
-
-
- TextTrackList.prototype.addTrack = function addTrack(track) {
- _TrackList.prototype.addTrack.call(this, track);
-
- /**
- * @listens TextTrack#modechange
- * @fires TrackList#change
- */
- track.addEventListener('modechange', bind(this, function () {
- this.trigger('change');
- }));
-
- var nonLanguageTextTrackKind = ['metadata', 'chapters'];
-
- if (nonLanguageTextTrackKind.indexOf(track.kind) === -1) {
- track.addEventListener('modechange', bind(this, function () {
- this.trigger('selectedlanguagechange');
- }));
- }
- };
-
- return TextTrackList;
- }(TrackList);
-
- /**
- * @file html-track-element-list.js
- */
-
- /**
- * The current list of {@link HtmlTrackElement}s.
- */
-
- var HtmlTrackElementList = function () {
-
- /**
- * Create an instance of this class.
- *
- * @param {HtmlTrackElement[]} [tracks=[]]
- * A list of `HtmlTrackElement` to instantiate the list with.
- */
- function HtmlTrackElementList() {
- var trackElements = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
- classCallCheck(this, HtmlTrackElementList);
-
- var list = this; // eslint-disable-line
-
- if (IS_IE8) {
- list = document_1.createElement('custom');
-
- for (var prop in HtmlTrackElementList.prototype) {
- if (prop !== 'constructor') {
- list[prop] = HtmlTrackElementList.prototype[prop];
- }
- }
- }
-
- list.trackElements_ = [];
-
- /**
- * @memberof HtmlTrackElementList
- * @member {number} length
- * The current number of `Track`s in the this Trackist.
- * @instance
- */
- Object.defineProperty(list, 'length', {
- get: function get$$1() {
- return this.trackElements_.length;
- }
- });
-
- for (var i = 0, length = trackElements.length; i < length; i++) {
- list.addTrackElement_(trackElements[i]);
- }
-
- if (IS_IE8) {
- return list;
- }
- }
-
- /**
- * Add an {@link HtmlTrackElement} to the `HtmlTrackElementList`
- *
- * @param {HtmlTrackElement} trackElement
- * The track element to add to the list.
- *
- * @private
- */
-
-
- HtmlTrackElementList.prototype.addTrackElement_ = function addTrackElement_(trackElement) {
- var index = this.trackElements_.length;
-
- if (!('' + index in this)) {
- Object.defineProperty(this, index, {
- get: function get$$1() {
- return this.trackElements_[index];
- }
- });
- }
-
- // Do not add duplicate elements
- if (this.trackElements_.indexOf(trackElement) === -1) {
- this.trackElements_.push(trackElement);
- }
- };
-
- /**
- * Get an {@link HtmlTrackElement} from the `HtmlTrackElementList` given an
- * {@link TextTrack}.
- *
- * @param {TextTrack} track
- * The track associated with a track element.
- *
- * @return {HtmlTrackElement|undefined}
- * The track element that was found or undefined.
- *
- * @private
- */
-
-
- HtmlTrackElementList.prototype.getTrackElementByTrack_ = function getTrackElementByTrack_(track) {
- var trackElement_ = void 0;
-
- for (var i = 0, length = this.trackElements_.length; i < length; i++) {
- if (track === this.trackElements_[i].track) {
- trackElement_ = this.trackElements_[i];
-
- break;
- }
- }
-
- return trackElement_;
- };
-
- /**
- * Remove a {@link HtmlTrackElement} from the `HtmlTrackElementList`
- *
- * @param {HtmlTrackElement} trackElement
- * The track element to remove from the list.
- *
- * @private
- */
-
-
- HtmlTrackElementList.prototype.removeTrackElement_ = function removeTrackElement_(trackElement) {
- for (var i = 0, length = this.trackElements_.length; i < length; i++) {
- if (trackElement === this.trackElements_[i]) {
- this.trackElements_.splice(i, 1);
-
- break;
- }
- }
- };
-
- return HtmlTrackElementList;
- }();
-
- /**
- * @file text-track-cue-list.js
- */
- /**
- * @typedef {Object} TextTrackCueList~TextTrackCue
- *
- * @property {string} id
- * The unique id for this text track cue
- *
- * @property {number} startTime
- * The start time for this text track cue
- *
- * @property {number} endTime
- * The end time for this text track cue
- *
- * @property {boolean} pauseOnExit
- * Pause when the end time is reached if true.
- *
- * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackcue}
- */
-
- /**
- * A List of TextTrackCues.
- *
- * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackcuelist}
- */
-
- var TextTrackCueList = function () {
-
- /**
- * Create an instance of this class..
- *
- * @param {Array} cues
- * A list of cues to be initialized with
- */
- function TextTrackCueList(cues) {
- classCallCheck(this, TextTrackCueList);
-
- var list = this; // eslint-disable-line
-
- if (IS_IE8) {
- list = document_1.createElement('custom');
-
- for (var prop in TextTrackCueList.prototype) {
- if (prop !== 'constructor') {
- list[prop] = TextTrackCueList.prototype[prop];
- }
- }
- }
-
- TextTrackCueList.prototype.setCues_.call(list, cues);
-
- /**
- * @memberof TextTrackCueList
- * @member {number} length
- * The current number of `TextTrackCue`s in the TextTrackCueList.
- * @instance
- */
- Object.defineProperty(list, 'length', {
- get: function get$$1() {
- return this.length_;
- }
- });
-
- if (IS_IE8) {
- return list;
- }
- }
-
- /**
- * A setter for cues in this list. Creates getters
- * an an index for the cues.
- *
- * @param {Array} cues
- * An array of cues to set
- *
- * @private
- */
-
-
- TextTrackCueList.prototype.setCues_ = function setCues_(cues) {
- var oldLength = this.length || 0;
- var i = 0;
- var l = cues.length;
-
- this.cues_ = cues;
- this.length_ = cues.length;
-
- var defineProp = function defineProp(index) {
- if (!('' + index in this)) {
- Object.defineProperty(this, '' + index, {
- get: function get$$1() {
- return this.cues_[index];
- }
- });
- }
- };
-
- if (oldLength < l) {
- i = oldLength;
-
- for (; i < l; i++) {
- defineProp.call(this, i);
- }
- }
- };
-
- /**
- * Get a `TextTrackCue` that is currently in the `TextTrackCueList` by id.
- *
- * @param {string} id
- * The id of the cue that should be searched for.
- *
- * @return {TextTrackCueList~TextTrackCue|null}
- * A single cue or null if none was found.
- */
-
-
- TextTrackCueList.prototype.getCueById = function getCueById(id) {
- var result = null;
-
- for (var i = 0, l = this.length; i < l; i++) {
- var cue = this[i];
-
- if (cue.id === id) {
- result = cue;
- break;
- }
- }
-
- return result;
- };
-
- return TextTrackCueList;
- }();
-
- /**
- * @file track-kinds.js
- */
-
- /**
- * All possible `VideoTrackKind`s
- *
- * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-videotrack-kind
- * @typedef VideoTrack~Kind
- * @enum
- */
- var VideoTrackKind = {
- alternative: 'alternative',
- captions: 'captions',
- main: 'main',
- sign: 'sign',
- subtitles: 'subtitles',
- commentary: 'commentary'
- };
-
- /**
- * All possible `AudioTrackKind`s
- *
- * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-audiotrack-kind
- * @typedef AudioTrack~Kind
- * @enum
- */
- var AudioTrackKind = {
- 'alternative': 'alternative',
- 'descriptions': 'descriptions',
- 'main': 'main',
- 'main-desc': 'main-desc',
- 'translation': 'translation',
- 'commentary': 'commentary'
- };
-
- /**
- * All possible `TextTrackKind`s
- *
- * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-texttrack-kind
- * @typedef TextTrack~Kind
- * @enum
- */
- var TextTrackKind = {
- subtitles: 'subtitles',
- captions: 'captions',
- descriptions: 'descriptions',
- chapters: 'chapters',
- metadata: 'metadata'
- };
-
- /**
- * All possible `TextTrackMode`s
- *
- * @see https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackmode
- * @typedef TextTrack~Mode
- * @enum
- */
- var TextTrackMode = {
- disabled: 'disabled',
- hidden: 'hidden',
- showing: 'showing'
- };
-
- /**
- * @file track.js
- */
- /**
- * A Track class that contains all of the common functionality for {@link AudioTrack},
- * {@link VideoTrack}, and {@link TextTrack}.
- *
- * > Note: This class should not be used directly
- *
- * @see {@link https://html.spec.whatwg.org/multipage/embedded-content.html}
- * @extends EventTarget
- * @abstract
- */
-
- var Track = function (_EventTarget) {
- inherits(Track, _EventTarget);
-
- /**
- * Create an instance of this class.
- *
- * @param {Object} [options={}]
- * Object of option names and values
- *
- * @param {string} [options.kind='']
- * A valid kind for the track type you are creating.
- *
- * @param {string} [options.id='vjs_track_' + Guid.newGUID()]
- * A unique id for this AudioTrack.
- *
- * @param {string} [options.label='']
- * The menu label for this track.
- *
- * @param {string} [options.language='']
- * A valid two character language code.
- *
- * @abstract
- */
- function Track() {
- var _ret;
-
- var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
- classCallCheck(this, Track);
-
- var _this = possibleConstructorReturn(this, _EventTarget.call(this));
-
- var track = _this; // eslint-disable-line
-
- if (IS_IE8) {
- track = document_1.createElement('custom');
- for (var prop in Track.prototype) {
- if (prop !== 'constructor') {
- track[prop] = Track.prototype[prop];
- }
- }
- }
-
- var trackProps = {
- id: options.id || 'vjs_track_' + newGUID(),
- kind: options.kind || '',
- label: options.label || '',
- language: options.language || ''
- };
-
- /**
- * @memberof Track
- * @member {string} id
- * The id of this track. Cannot be changed after creation.
- * @instance
- *
- * @readonly
- */
-
- /**
- * @memberof Track
- * @member {string} kind
- * The kind of track that this is. Cannot be changed after creation.
- * @instance
- *
- * @readonly
- */
-
- /**
- * @memberof Track
- * @member {string} label
- * The label of this track. Cannot be changed after creation.
- * @instance
- *
- * @readonly
- */
-
- /**
- * @memberof Track
- * @member {string} language
- * The two letter language code for this track. Cannot be changed after
- * creation.
- * @instance
- *
- * @readonly
- */
-
- var _loop = function _loop(key) {
- Object.defineProperty(track, key, {
- get: function get$$1() {
- return trackProps[key];
- },
- set: function set$$1() {}
- });
- };
-
- for (var key in trackProps) {
- _loop(key);
- }
-
- return _ret = track, possibleConstructorReturn(_this, _ret);
- }
-
- return Track;
- }(EventTarget);
-
- /**
- * @file url.js
- * @module url
- */
- /**
- * @typedef {Object} url:URLObject
- *
- * @property {string} protocol
- * The protocol of the url that was parsed.
- *
- * @property {string} hostname
- * The hostname of the url that was parsed.
- *
- * @property {string} port
- * The port of the url that was parsed.
- *
- * @property {string} pathname
- * The pathname of the url that was parsed.
- *
- * @property {string} search
- * The search query of the url that was parsed.
- *
- * @property {string} hash
- * The hash of the url that was parsed.
- *
- * @property {string} host
- * The host of the url that was parsed.
- */
-
- /**
- * Resolve and parse the elements of a URL.
- *
- * @param {String} url
- * The url to parse
- *
- * @return {url:URLObject}
- * An object of url details
- */
- var parseUrl = function parseUrl(url) {
- var props = ['protocol', 'hostname', 'port', 'pathname', 'search', 'hash', 'host'];
-
- // add the url to an anchor and let the browser parse the URL
- var a = document_1.createElement('a');
-
- a.href = url;
-
- // IE8 (and 9?) Fix
- // ie8 doesn't parse the URL correctly until the anchor is actually
- // added to the body, and an innerHTML is needed to trigger the parsing
- var addToBody = a.host === '' && a.protocol !== 'file:';
- var div = void 0;
-
- if (addToBody) {
- div = document_1.createElement('div');
- div.innerHTML = '';
- a = div.firstChild;
- // prevent the div from affecting layout
- div.setAttribute('style', 'display:none; position:absolute;');
- document_1.body.appendChild(div);
- }
-
- // Copy the specific URL properties to a new object
- // This is also needed for IE8 because the anchor loses its
- // properties when it's removed from the dom
- var details = {};
-
- for (var i = 0; i < props.length; i++) {
- details[props[i]] = a[props[i]];
- }
-
- // IE9 adds the port to the host property unlike everyone else. If
- // a port identifier is added for standard ports, strip it.
- if (details.protocol === 'http:') {
- details.host = details.host.replace(/:80$/, '');
- }
-
- if (details.protocol === 'https:') {
- details.host = details.host.replace(/:443$/, '');
- }
-
- if (!details.protocol) {
- details.protocol = window_1.location.protocol;
- }
-
- if (addToBody) {
- document_1.body.removeChild(div);
- }
-
- return details;
- };
-
- /**
- * Get absolute version of relative URL. Used to tell flash correct URL.
- *
- *
- * @param {string} url
- * URL to make absolute
- *
- * @return {string}
- * Absolute URL
- *
- * @see http://stackoverflow.com/questions/470832/getting-an-absolute-url-from-a-relative-one-ie6-issue
- */
- var getAbsoluteURL = function getAbsoluteURL(url) {
- // Check if absolute URL
- if (!url.match(/^https?:\/\//)) {
- // Convert to absolute URL. Flash hosted off-site needs an absolute URL.
- var div = document_1.createElement('div');
-
- div.innerHTML = 'x';
- url = div.firstChild.href;
- }
-
- return url;
- };
-
- /**
- * Returns the extension of the passed file name. It will return an empty string
- * if passed an invalid path.
- *
- * @param {string} path
- * The fileName path like '/path/to/file.mp4'
- *
- * @returns {string}
- * The extension in lower case or an empty string if no
- * extension could be found.
- */
- var getFileExtension = function getFileExtension(path) {
- if (typeof path === 'string') {
- var splitPathRe = /^(\/?)([\s\S]*?)((?:\.{1,2}|[^\/]+?)(\.([^\.\/\?]+)))(?:[\/]*|[\?].*)$/i;
- var pathParts = splitPathRe.exec(path);
-
- if (pathParts) {
- return pathParts.pop().toLowerCase();
- }
- }
-
- return '';
- };
-
- /**
- * Returns whether the url passed is a cross domain request or not.
- *
- * @param {string} url
- * The url to check.
- *
- * @return {boolean}
- * Whether it is a cross domain request or not.
- */
- var isCrossOrigin = function isCrossOrigin(url) {
- var winLoc = window_1.location;
- var urlInfo = parseUrl(url);
-
- // IE8 protocol relative urls will return ':' for protocol
- var srcProtocol = urlInfo.protocol === ':' ? winLoc.protocol : urlInfo.protocol;
-
- // Check if url is for another domain/origin
- // IE8 doesn't know location.origin, so we won't rely on it here
- var crossOrigin = srcProtocol + urlInfo.host !== winLoc.protocol + winLoc.host;
-
- return crossOrigin;
- };
-
- var Url = (Object.freeze || Object)({
- parseUrl: parseUrl,
- getAbsoluteURL: getAbsoluteURL,
- getFileExtension: getFileExtension,
- isCrossOrigin: isCrossOrigin
- });
-
- var isFunction_1 = isFunction;
-
- var toString$1 = Object.prototype.toString;
-
- function isFunction (fn) {
- var string = toString$1.call(fn);
- return string === '[object Function]' ||
- (typeof fn === 'function' && string !== '[object RegExp]') ||
- (typeof window !== 'undefined' &&
- // IE8 and below
- (fn === window.setTimeout ||
- fn === window.alert ||
- fn === window.confirm ||
- fn === window.prompt))
- }
-
- var trim_1 = createCommonjsModule(function (module, exports) {
- exports = module.exports = trim;
-
- function trim(str){
- return str.replace(/^\s*|\s*$/g, '');
- }
-
- exports.left = function(str){
- return str.replace(/^\s*/, '');
- };
-
- exports.right = function(str){
- return str.replace(/\s*$/, '');
- };
- });
-
- var forEach_1 = forEach;
-
- var toString$2 = Object.prototype.toString;
- var hasOwnProperty = Object.prototype.hasOwnProperty;
-
- function forEach(list, iterator, context) {
- if (!isFunction_1(iterator)) {
- throw new TypeError('iterator must be a function')
- }
-
- if (arguments.length < 3) {
- context = this;
- }
-
- if (toString$2.call(list) === '[object Array]')
- forEachArray$1(list, iterator, context);
- else if (typeof list === 'string')
- forEachString(list, iterator, context);
- else
- forEachObject(list, iterator, context);
- }
-
- function forEachArray$1(array, iterator, context) {
- for (var i = 0, len = array.length; i < len; i++) {
- if (hasOwnProperty.call(array, i)) {
- iterator.call(context, array[i], i, array);
- }
- }
- }
-
- function forEachString(string, iterator, context) {
- for (var i = 0, len = string.length; i < len; i++) {
- // no such thing as a sparse string.
- iterator.call(context, string.charAt(i), i, string);
- }
- }
-
- function forEachObject(object, iterator, context) {
- for (var k in object) {
- if (hasOwnProperty.call(object, k)) {
- iterator.call(context, object[k], k, object);
- }
- }
- }
-
- var isArray = function(arg) {
- return Object.prototype.toString.call(arg) === '[object Array]';
- };
-
- var parseHeaders = function (headers) {
- if (!headers)
- return {}
-
- var result = {};
-
- forEach_1(
- trim_1(headers).split('\n')
- , function (row) {
- var index = row.indexOf(':')
- , key = trim_1(row.slice(0, index)).toLowerCase()
- , value = trim_1(row.slice(index + 1));
-
- if (typeof(result[key]) === 'undefined') {
- result[key] = value;
- } else if (isArray(result[key])) {
- result[key].push(value);
- } else {
- result[key] = [ result[key], value ];
- }
- }
- );
-
- return result
- };
-
- var immutable = extend;
-
- var hasOwnProperty$1 = Object.prototype.hasOwnProperty;
-
- function extend() {
- var target = {};
-
- for (var i = 0; i < arguments.length; i++) {
- var source = arguments[i];
-
- for (var key in source) {
- if (hasOwnProperty$1.call(source, key)) {
- target[key] = source[key];
- }
- }
- }
-
- return target
- }
-
- var xhr = createXHR;
- createXHR.XMLHttpRequest = window_1.XMLHttpRequest || noop;
- createXHR.XDomainRequest = "withCredentials" in (new createXHR.XMLHttpRequest()) ? createXHR.XMLHttpRequest : window_1.XDomainRequest;
-
- forEachArray(["get", "put", "post", "patch", "head", "delete"], function(method) {
- createXHR[method === "delete" ? "del" : method] = function(uri, options, callback) {
- options = initParams(uri, options, callback);
- options.method = method.toUpperCase();
- return _createXHR(options)
- };
- });
-
- function forEachArray(array, iterator) {
- for (var i = 0; i < array.length; i++) {
- iterator(array[i]);
- }
- }
-
- function isEmpty(obj){
- for(var i in obj){
- if(obj.hasOwnProperty(i)) return false
- }
- return true
- }
-
- function initParams(uri, options, callback) {
- var params = uri;
-
- if (isFunction_1(options)) {
- callback = options;
- if (typeof uri === "string") {
- params = {uri:uri};
- }
- } else {
- params = immutable(options, {uri: uri});
- }
-
- params.callback = callback;
- return params
- }
-
- function createXHR(uri, options, callback) {
- options = initParams(uri, options, callback);
- return _createXHR(options)
- }
-
- function _createXHR(options) {
- if(typeof options.callback === "undefined"){
- throw new Error("callback argument missing")
- }
-
- var called = false;
- var callback = function cbOnce(err, response, body){
- if(!called){
- called = true;
- options.callback(err, response, body);
- }
- };
-
- function readystatechange() {
- if (xhr.readyState === 4) {
- setTimeout(loadFunc, 0);
- }
- }
-
- function getBody() {
- // Chrome with requestType=blob throws errors arround when even testing access to responseText
- var body = undefined;
-
- if (xhr.response) {
- body = xhr.response;
- } else {
- body = xhr.responseText || getXml(xhr);
- }
-
- if (isJson) {
- try {
- body = JSON.parse(body);
- } catch (e) {}
- }
-
- return body
- }
-
- function errorFunc(evt) {
- clearTimeout(timeoutTimer);
- if(!(evt instanceof Error)){
- evt = new Error("" + (evt || "Unknown XMLHttpRequest Error") );
- }
- evt.statusCode = 0;
- return callback(evt, failureResponse)
- }
-
- // will load the data & process the response in a special response object
- function loadFunc() {
- if (aborted) return
- var status;
- clearTimeout(timeoutTimer);
- if(options.useXDR && xhr.status===undefined) {
- //IE8 CORS GET successful response doesn't have a status field, but body is fine
- status = 200;
- } else {
- status = (xhr.status === 1223 ? 204 : xhr.status);
- }
- var response = failureResponse;
- var err = null;
-
- if (status !== 0){
- response = {
- body: getBody(),
- statusCode: status,
- method: method,
- headers: {},
- url: uri,
- rawRequest: xhr
- };
- if(xhr.getAllResponseHeaders){ //remember xhr can in fact be XDR for CORS in IE
- response.headers = parseHeaders(xhr.getAllResponseHeaders());
- }
- } else {
- err = new Error("Internal XMLHttpRequest Error");
- }
- return callback(err, response, response.body)
- }
-
- var xhr = options.xhr || null;
-
- if (!xhr) {
- if (options.cors || options.useXDR) {
- xhr = new createXHR.XDomainRequest();
- }else{
- xhr = new createXHR.XMLHttpRequest();
- }
- }
-
- var key;
- var aborted;
- var uri = xhr.url = options.uri || options.url;
- var method = xhr.method = options.method || "GET";
- var body = options.body || options.data;
- var headers = xhr.headers = options.headers || {};
- var sync = !!options.sync;
- var isJson = false;
- var timeoutTimer;
- var failureResponse = {
- body: undefined,
- headers: {},
- statusCode: 0,
- method: method,
- url: uri,
- rawRequest: xhr
- };
-
- if ("json" in options && options.json !== false) {
- isJson = true;
- headers["accept"] || headers["Accept"] || (headers["Accept"] = "application/json"); //Don't override existing accept header declared by user
- if (method !== "GET" && method !== "HEAD") {
- headers["content-type"] || headers["Content-Type"] || (headers["Content-Type"] = "application/json"); //Don't override existing accept header declared by user
- body = JSON.stringify(options.json === true ? body : options.json);
- }
- }
-
- xhr.onreadystatechange = readystatechange;
- xhr.onload = loadFunc;
- xhr.onerror = errorFunc;
- // IE9 must have onprogress be set to a unique function.
- xhr.onprogress = function () {
- // IE must die
- };
- xhr.onabort = function(){
- aborted = true;
- };
- xhr.ontimeout = errorFunc;
- xhr.open(method, uri, !sync, options.username, options.password);
- //has to be after open
- if(!sync) {
- xhr.withCredentials = !!options.withCredentials;
- }
- // Cannot set timeout with sync request
- // not setting timeout on the xhr object, because of old webkits etc. not handling that correctly
- // both npm's request and jquery 1.x use this kind of timeout, so this is being consistent
- if (!sync && options.timeout > 0 ) {
- timeoutTimer = setTimeout(function(){
- if (aborted) return
- aborted = true;//IE9 may still call readystatechange
- xhr.abort("timeout");
- var e = new Error("XMLHttpRequest timeout");
- e.code = "ETIMEDOUT";
- errorFunc(e);
- }, options.timeout );
- }
-
- if (xhr.setRequestHeader) {
- for(key in headers){
- if(headers.hasOwnProperty(key)){
- xhr.setRequestHeader(key, headers[key]);
- }
- }
- } else if (options.headers && !isEmpty(options.headers)) {
- throw new Error("Headers cannot be set on an XDomainRequest object")
- }
-
- if ("responseType" in options) {
- xhr.responseType = options.responseType;
- }
-
- if ("beforeSend" in options &&
- typeof options.beforeSend === "function"
- ) {
- options.beforeSend(xhr);
- }
-
- // Microsoft Edge browser sends "undefined" when send is called with undefined value.
- // XMLHttpRequest spec says to pass null as body to indicate no body
- // See https://github.com/naugtur/xhr/issues/100.
- xhr.send(body || null);
-
- return xhr
-
-
- }
-
- function getXml(xhr) {
- if (xhr.responseType === "document") {
- return xhr.responseXML
- }
- var firefoxBugTakenEffect = xhr.responseXML && xhr.responseXML.documentElement.nodeName === "parsererror";
- if (xhr.responseType === "" && !firefoxBugTakenEffect) {
- return xhr.responseXML
- }
-
- return null
- }
-
- function noop() {}
-
- /**
- * @file text-track.js
- */
- /**
- * Takes a webvtt file contents and parses it into cues
- *
- * @param {string} srcContent
- * webVTT file contents
- *
- * @param {TextTrack} track
- * TextTrack to add cues to. Cues come from the srcContent.
- *
- * @private
- */
- var parseCues = function parseCues(srcContent, track) {
- var parser = new window_1.WebVTT.Parser(window_1, window_1.vttjs, window_1.WebVTT.StringDecoder());
- var errors = [];
-
- parser.oncue = function (cue) {
- track.addCue(cue);
- };
-
- parser.onparsingerror = function (error) {
- errors.push(error);
- };
-
- parser.onflush = function () {
- track.trigger({
- type: 'loadeddata',
- target: track
- });
- };
-
- parser.parse(srcContent);
- if (errors.length > 0) {
- if (window_1.console && window_1.console.groupCollapsed) {
- window_1.console.groupCollapsed('Text Track parsing errors for ' + track.src);
- }
- errors.forEach(function (error) {
- return log$1.error(error);
- });
- if (window_1.console && window_1.console.groupEnd) {
- window_1.console.groupEnd();
- }
- }
-
- parser.flush();
- };
-
- /**
- * Load a `TextTrack` from a specifed url.
- *
- * @param {string} src
- * Url to load track from.
- *
- * @param {TextTrack} track
- * Track to add cues to. Comes from the content at the end of `url`.
- *
- * @private
- */
- var loadTrack = function loadTrack(src, track) {
- var opts = {
- uri: src
- };
- var crossOrigin = isCrossOrigin(src);
-
- if (crossOrigin) {
- opts.cors = crossOrigin;
- }
-
- xhr(opts, bind(this, function (err, response, responseBody) {
- if (err) {
- return log$1.error(err, response);
- }
-
- track.loaded_ = true;
-
- // Make sure that vttjs has loaded, otherwise, wait till it finished loading
- // NOTE: this is only used for the alt/video.novtt.js build
- if (typeof window_1.WebVTT !== 'function') {
- if (track.tech_) {
- var loadHandler = function loadHandler() {
- return parseCues(responseBody, track);
- };
-
- track.tech_.on('vttjsloaded', loadHandler);
- track.tech_.on('vttjserror', function () {
- log$1.error('vttjs failed to load, stopping trying to process ' + track.src);
- track.tech_.off('vttjsloaded', loadHandler);
- });
- }
- } else {
- parseCues(responseBody, track);
- }
- }));
- };
-
- /**
- * A representation of a single `TextTrack`.
- *
- * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#texttrack}
- * @extends Track
- */
-
- var TextTrack = function (_Track) {
- inherits(TextTrack, _Track);
-
- /**
- * Create an instance of this class.
- *
- * @param {Object} options={}
- * Object of option names and values
- *
- * @param {Tech} options.tech
- * A reference to the tech that owns this TextTrack.
- *
- * @param {TextTrack~Kind} [options.kind='subtitles']
- * A valid text track kind.
- *
- * @param {TextTrack~Mode} [options.mode='disabled']
- * A valid text track mode.
- *
- * @param {string} [options.id='vjs_track_' + Guid.newGUID()]
- * A unique id for this TextTrack.
- *
- * @param {string} [options.label='']
- * The menu label for this track.
- *
- * @param {string} [options.language='']
- * A valid two character language code.
- *
- * @param {string} [options.srclang='']
- * A valid two character language code. An alternative, but deprioritized
- * vesion of `options.language`
- *
- * @param {string} [options.src]
- * A url to TextTrack cues.
- *
- * @param {boolean} [options.default]
- * If this track should default to on or off.
- */
- function TextTrack() {
- var _this, _ret;
-
- var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
- classCallCheck(this, TextTrack);
-
- if (!options.tech) {
- throw new Error('A tech was not provided.');
- }
-
- var settings = mergeOptions(options, {
- kind: TextTrackKind[options.kind] || 'subtitles',
- language: options.language || options.srclang || ''
- });
- var mode = TextTrackMode[settings.mode] || 'disabled';
- var default_ = settings['default'];
-
- if (settings.kind === 'metadata' || settings.kind === 'chapters') {
- mode = 'hidden';
- }
- // on IE8 this will be a document element
- // for every other browser this will be a normal object
- var tt = (_this = possibleConstructorReturn(this, _Track.call(this, settings)), _this);
-
- tt.tech_ = settings.tech;
-
- if (IS_IE8) {
- for (var prop in TextTrack.prototype) {
- if (prop !== 'constructor') {
- tt[prop] = TextTrack.prototype[prop];
- }
- }
- }
-
- tt.cues_ = [];
- tt.activeCues_ = [];
-
- var cues = new TextTrackCueList(tt.cues_);
- var activeCues = new TextTrackCueList(tt.activeCues_);
- var changed = false;
- var timeupdateHandler = bind(tt, function () {
-
- // Accessing this.activeCues for the side-effects of updating itself
- // due to it's nature as a getter function. Do not remove or cues will
- // stop updating!
- /* eslint-disable no-unused-expressions */
- this.activeCues;
- /* eslint-enable no-unused-expressions */
- if (changed) {
- this.trigger('cuechange');
- changed = false;
- }
- });
-
- if (mode !== 'disabled') {
- tt.tech_.ready(function () {
- tt.tech_.on('timeupdate', timeupdateHandler);
- }, true);
- }
-
- /**
- * @memberof TextTrack
- * @member {boolean} default
- * If this track was set to be on or off by default. Cannot be changed after
- * creation.
- * @instance
- *
- * @readonly
- */
- Object.defineProperty(tt, 'default', {
- get: function get$$1() {
- return default_;
- },
- set: function set$$1() {}
- });
-
- /**
- * @memberof TextTrack
- * @member {string} mode
- * Set the mode of this TextTrack to a valid {@link TextTrack~Mode}. Will
- * not be set if setting to an invalid mode.
- * @instance
- *
- * @fires TextTrack#modechange
- */
- Object.defineProperty(tt, 'mode', {
- get: function get$$1() {
- return mode;
- },
- set: function set$$1(newMode) {
- var _this2 = this;
-
- if (!TextTrackMode[newMode]) {
- return;
- }
- mode = newMode;
- if (mode === 'showing') {
-
- this.tech_.ready(function () {
- _this2.tech_.on('timeupdate', timeupdateHandler);
- }, true);
- }
- /**
- * An event that fires when mode changes on this track. This allows
- * the TextTrackList that holds this track to act accordingly.
- *
- * > Note: This is not part of the spec!
- *
- * @event TextTrack#modechange
- * @type {EventTarget~Event}
- */
- this.trigger('modechange');
- }
- });
-
- /**
- * @memberof TextTrack
- * @member {TextTrackCueList} cues
- * The text track cue list for this TextTrack.
- * @instance
- */
- Object.defineProperty(tt, 'cues', {
- get: function get$$1() {
- if (!this.loaded_) {
- return null;
- }
-
- return cues;
- },
- set: function set$$1() {}
- });
-
- /**
- * @memberof TextTrack
- * @member {TextTrackCueList} activeCues
- * The list text track cues that are currently active for this TextTrack.
- * @instance
- */
- Object.defineProperty(tt, 'activeCues', {
- get: function get$$1() {
- if (!this.loaded_) {
- return null;
- }
-
- // nothing to do
- if (this.cues.length === 0) {
- return activeCues;
- }
-
- var ct = this.tech_.currentTime();
- var active = [];
-
- for (var i = 0, l = this.cues.length; i < l; i++) {
- var cue = this.cues[i];
-
- if (cue.startTime <= ct && cue.endTime >= ct) {
- active.push(cue);
- } else if (cue.startTime === cue.endTime && cue.startTime <= ct && cue.startTime + 0.5 >= ct) {
- active.push(cue);
- }
- }
-
- changed = false;
-
- if (active.length !== this.activeCues_.length) {
- changed = true;
- } else {
- for (var _i = 0; _i < active.length; _i++) {
- if (this.activeCues_.indexOf(active[_i]) === -1) {
- changed = true;
- }
- }
- }
-
- this.activeCues_ = active;
- activeCues.setCues_(this.activeCues_);
-
- return activeCues;
- },
- set: function set$$1() {}
- });
-
- if (settings.src) {
- tt.src = settings.src;
- loadTrack(settings.src, tt);
- } else {
- tt.loaded_ = true;
- }
-
- return _ret = tt, possibleConstructorReturn(_this, _ret);
- }
-
- /**
- * Add a cue to the internal list of cues.
- *
- * @param {TextTrack~Cue} cue
- * The cue to add to our internal list
- */
-
-
- TextTrack.prototype.addCue = function addCue(originalCue) {
- var cue = originalCue;
-
- if (window_1.vttjs && !(originalCue instanceof window_1.vttjs.VTTCue)) {
- cue = new window_1.vttjs.VTTCue(originalCue.startTime, originalCue.endTime, originalCue.text);
-
- for (var prop in originalCue) {
- if (!(prop in cue)) {
- cue[prop] = originalCue[prop];
- }
- }
-
- // make sure that `id` is copied over
- cue.id = originalCue.id;
- cue.originalCue_ = originalCue;
- }
-
- var tracks = this.tech_.textTracks();
-
- for (var i = 0; i < tracks.length; i++) {
- if (tracks[i] !== this) {
- tracks[i].removeCue(cue);
- }
- }
-
- this.cues_.push(cue);
- this.cues.setCues_(this.cues_);
- };
-
- /**
- * Remove a cue from our internal list
- *
- * @param {TextTrack~Cue} removeCue
- * The cue to remove from our internal list
- */
-
-
- TextTrack.prototype.removeCue = function removeCue(_removeCue) {
- var i = this.cues_.length;
-
- while (i--) {
- var cue = this.cues_[i];
-
- if (cue === _removeCue || cue.originalCue_ && cue.originalCue_ === _removeCue) {
- this.cues_.splice(i, 1);
- this.cues.setCues_(this.cues_);
- break;
- }
- }
- };
-
- return TextTrack;
- }(Track);
-
- /**
- * cuechange - One or more cues in the track have become active or stopped being active.
- */
-
-
- TextTrack.prototype.allowedEvents_ = {
- cuechange: 'cuechange'
- };
-
- /**
- * A representation of a single `AudioTrack`. If it is part of an {@link AudioTrackList}
- * only one `AudioTrack` in the list will be enabled at a time.
- *
- * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#audiotrack}
- * @extends Track
- */
-
- var AudioTrack = function (_Track) {
- inherits(AudioTrack, _Track);
-
- /**
- * Create an instance of this class.
- *
- * @param {Object} [options={}]
- * Object of option names and values
- *
- * @param {AudioTrack~Kind} [options.kind='']
- * A valid audio track kind
- *
- * @param {string} [options.id='vjs_track_' + Guid.newGUID()]
- * A unique id for this AudioTrack.
- *
- * @param {string} [options.label='']
- * The menu label for this track.
- *
- * @param {string} [options.language='']
- * A valid two character language code.
- *
- * @param {boolean} [options.enabled]
- * If this track is the one that is currently playing. If this track is part of
- * an {@link AudioTrackList}, only one {@link AudioTrack} will be enabled.
- */
- function AudioTrack() {
- var _this, _ret;
-
- var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
- classCallCheck(this, AudioTrack);
-
- var settings = mergeOptions(options, {
- kind: AudioTrackKind[options.kind] || ''
- });
- // on IE8 this will be a document element
- // for every other browser this will be a normal object
- var track = (_this = possibleConstructorReturn(this, _Track.call(this, settings)), _this);
- var enabled = false;
-
- if (IS_IE8) {
- for (var prop in AudioTrack.prototype) {
- if (prop !== 'constructor') {
- track[prop] = AudioTrack.prototype[prop];
- }
- }
- }
- /**
- * @memberof AudioTrack
- * @member {boolean} enabled
- * If this `AudioTrack` is enabled or not. When setting this will
- * fire {@link AudioTrack#enabledchange} if the state of enabled is changed.
- * @instance
- *
- * @fires VideoTrack#selectedchange
- */
- Object.defineProperty(track, 'enabled', {
- get: function get$$1() {
- return enabled;
- },
- set: function set$$1(newEnabled) {
- // an invalid or unchanged value
- if (typeof newEnabled !== 'boolean' || newEnabled === enabled) {
- return;
- }
- enabled = newEnabled;
-
- /**
- * An event that fires when enabled changes on this track. This allows
- * the AudioTrackList that holds this track to act accordingly.
- *
- * > Note: This is not part of the spec! Native tracks will do
- * this internally without an event.
- *
- * @event AudioTrack#enabledchange
- * @type {EventTarget~Event}
- */
- this.trigger('enabledchange');
- }
- });
-
- // if the user sets this track to selected then
- // set selected to that true value otherwise
- // we keep it false
- if (settings.enabled) {
- track.enabled = settings.enabled;
- }
- track.loaded_ = true;
-
- return _ret = track, possibleConstructorReturn(_this, _ret);
- }
-
- return AudioTrack;
- }(Track);
-
- /**
- * A representation of a single `VideoTrack`.
- *
- * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#videotrack}
- * @extends Track
- */
-
- var VideoTrack = function (_Track) {
- inherits(VideoTrack, _Track);
-
- /**
- * Create an instance of this class.
- *
- * @param {Object} [options={}]
- * Object of option names and values
- *
- * @param {string} [options.kind='']
- * A valid {@link VideoTrack~Kind}
- *
- * @param {string} [options.id='vjs_track_' + Guid.newGUID()]
- * A unique id for this AudioTrack.
- *
- * @param {string} [options.label='']
- * The menu label for this track.
- *
- * @param {string} [options.language='']
- * A valid two character language code.
- *
- * @param {boolean} [options.selected]
- * If this track is the one that is currently playing.
- */
- function VideoTrack() {
- var _this, _ret;
-
- var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
- classCallCheck(this, VideoTrack);
-
- var settings = mergeOptions(options, {
- kind: VideoTrackKind[options.kind] || ''
- });
-
- // on IE8 this will be a document element
- // for every other browser this will be a normal object
- var track = (_this = possibleConstructorReturn(this, _Track.call(this, settings)), _this);
- var selected = false;
-
- if (IS_IE8) {
- for (var prop in VideoTrack.prototype) {
- if (prop !== 'constructor') {
- track[prop] = VideoTrack.prototype[prop];
- }
- }
- }
-
- /**
- * @memberof VideoTrack
- * @member {boolean} selected
- * If this `VideoTrack` is selected or not. When setting this will
- * fire {@link VideoTrack#selectedchange} if the state of selected changed.
- * @instance
- *
- * @fires VideoTrack#selectedchange
- */
- Object.defineProperty(track, 'selected', {
- get: function get$$1() {
- return selected;
- },
- set: function set$$1(newSelected) {
- // an invalid or unchanged value
- if (typeof newSelected !== 'boolean' || newSelected === selected) {
- return;
- }
- selected = newSelected;
-
- /**
- * An event that fires when selected changes on this track. This allows
- * the VideoTrackList that holds this track to act accordingly.
- *
- * > Note: This is not part of the spec! Native tracks will do
- * this internally without an event.
- *
- * @event VideoTrack#selectedchange
- * @type {EventTarget~Event}
- */
- this.trigger('selectedchange');
- }
- });
-
- // if the user sets this track to selected then
- // set selected to that true value otherwise
- // we keep it false
- if (settings.selected) {
- track.selected = settings.selected;
- }
-
- return _ret = track, possibleConstructorReturn(_this, _ret);
- }
-
- return VideoTrack;
- }(Track);
-
- /**
- * @file html-track-element.js
- */
-
- /**
- * @memberof HTMLTrackElement
- * @typedef {HTMLTrackElement~ReadyState}
- * @enum {number}
- */
- var NONE = 0;
- var LOADING = 1;
- var LOADED = 2;
- var ERROR = 3;
-
- /**
- * A single track represented in the DOM.
- *
- * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#htmltrackelement}
- * @extends EventTarget
- */
-
- var HTMLTrackElement = function (_EventTarget) {
- inherits(HTMLTrackElement, _EventTarget);
-
- /**
- * Create an instance of this class.
- *
- * @param {Object} options={}
- * Object of option names and values
- *
- * @param {Tech} options.tech
- * A reference to the tech that owns this HTMLTrackElement.
- *
- * @param {TextTrack~Kind} [options.kind='subtitles']
- * A valid text track kind.
- *
- * @param {TextTrack~Mode} [options.mode='disabled']
- * A valid text track mode.
- *
- * @param {string} [options.id='vjs_track_' + Guid.newGUID()]
- * A unique id for this TextTrack.
- *
- * @param {string} [options.label='']
- * The menu label for this track.
- *
- * @param {string} [options.language='']
- * A valid two character language code.
- *
- * @param {string} [options.srclang='']
- * A valid two character language code. An alternative, but deprioritized
- * vesion of `options.language`
- *
- * @param {string} [options.src]
- * A url to TextTrack cues.
- *
- * @param {boolean} [options.default]
- * If this track should default to on or off.
- */
- function HTMLTrackElement() {
- var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
- classCallCheck(this, HTMLTrackElement);
-
- var _this = possibleConstructorReturn(this, _EventTarget.call(this));
-
- var readyState = void 0;
- var trackElement = _this; // eslint-disable-line
-
- if (IS_IE8) {
- trackElement = document_1.createElement('custom');
-
- for (var prop in HTMLTrackElement.prototype) {
- if (prop !== 'constructor') {
- trackElement[prop] = HTMLTrackElement.prototype[prop];
- }
- }
- }
-
- var track = new TextTrack(options);
-
- trackElement.kind = track.kind;
- trackElement.src = track.src;
- trackElement.srclang = track.language;
- trackElement.label = track.label;
- trackElement['default'] = track['default'];
-
- /**
- * @memberof HTMLTrackElement
- * @member {HTMLTrackElement~ReadyState} readyState
- * The current ready state of the track element.
- * @instance
- */
- Object.defineProperty(trackElement, 'readyState', {
- get: function get$$1() {
- return readyState;
- }
- });
-
- /**
- * @memberof HTMLTrackElement
- * @member {TextTrack} track
- * The underlying TextTrack object.
- * @instance
- *
- */
- Object.defineProperty(trackElement, 'track', {
- get: function get$$1() {
- return track;
- }
- });
-
- readyState = NONE;
-
- /**
- * @listens TextTrack#loadeddata
- * @fires HTMLTrackElement#load
- */
- track.addEventListener('loadeddata', function () {
- readyState = LOADED;
-
- trackElement.trigger({
- type: 'load',
- target: trackElement
- });
- });
-
- if (IS_IE8) {
- var _ret;
-
- return _ret = trackElement, possibleConstructorReturn(_this, _ret);
- }
- return _this;
- }
-
- return HTMLTrackElement;
- }(EventTarget);
-
- HTMLTrackElement.prototype.allowedEvents_ = {
- load: 'load'
- };
-
- HTMLTrackElement.NONE = NONE;
- HTMLTrackElement.LOADING = LOADING;
- HTMLTrackElement.LOADED = LOADED;
- HTMLTrackElement.ERROR = ERROR;
-
- /*
- * This file contains all track properties that are used in
- * player.js, tech.js, html5.js and possibly other techs in the future.
- */
-
- var NORMAL = {
- audio: {
- ListClass: AudioTrackList,
- TrackClass: AudioTrack,
- capitalName: 'Audio'
- },
- video: {
- ListClass: VideoTrackList,
- TrackClass: VideoTrack,
- capitalName: 'Video'
- },
- text: {
- ListClass: TextTrackList,
- TrackClass: TextTrack,
- capitalName: 'Text'
- }
- };
-
- Object.keys(NORMAL).forEach(function (type) {
- NORMAL[type].getterName = type + 'Tracks';
- NORMAL[type].privateName = type + 'Tracks_';
- });
-
- var REMOTE = {
- remoteText: {
- ListClass: TextTrackList,
- TrackClass: TextTrack,
- capitalName: 'RemoteText',
- getterName: 'remoteTextTracks',
- privateName: 'remoteTextTracks_'
- },
- remoteTextEl: {
- ListClass: HtmlTrackElementList,
- TrackClass: HTMLTrackElement,
- capitalName: 'RemoteTextTrackEls',
- getterName: 'remoteTextTrackEls',
- privateName: 'remoteTextTrackEls_'
- }
- };
-
- var ALL = mergeOptions(NORMAL, REMOTE);
-
- REMOTE.names = Object.keys(REMOTE);
- NORMAL.names = Object.keys(NORMAL);
- ALL.names = [].concat(REMOTE.names).concat(NORMAL.names);
-
- /**
- * Copyright 2013 vtt.js Contributors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
- var _objCreate = Object.create || (function() {
- function F() {}
- return function(o) {
- if (arguments.length !== 1) {
- throw new Error('Object.create shim only accepts one parameter.');
- }
- F.prototype = o;
- return new F();
- };
- })();
-
-// Creates a new ParserError object from an errorData object. The errorData
-// object should have default code and message properties. The default message
-// property can be overriden by passing in a message parameter.
-// See ParsingError.Errors below for acceptable errors.
- function ParsingError(errorData, message) {
- this.name = "ParsingError";
- this.code = errorData.code;
- this.message = message || errorData.message;
- }
- ParsingError.prototype = _objCreate(Error.prototype);
- ParsingError.prototype.constructor = ParsingError;
-
-// ParsingError metadata for acceptable ParsingErrors.
- ParsingError.Errors = {
- BadSignature: {
- code: 0,
- message: "Malformed WebVTT signature."
- },
- BadTimeStamp: {
- code: 1,
- message: "Malformed time stamp."
- }
- };
-
-// Try to parse input as a time stamp.
- function parseTimeStamp(input) {
-
- function computeSeconds(h, m, s, f) {
- return (h | 0) * 3600 + (m | 0) * 60 + (s | 0) + (f | 0) / 1000;
- }
-
- var m = input.match(/^(\d+):(\d{2})(:\d{2})?\.(\d{3})/);
- if (!m) {
- return null;
- }
-
- if (m[3]) {
- // Timestamp takes the form of [hours]:[minutes]:[seconds].[milliseconds]
- return computeSeconds(m[1], m[2], m[3].replace(":", ""), m[4]);
- } else if (m[1] > 59) {
- // Timestamp takes the form of [hours]:[minutes].[milliseconds]
- // First position is hours as it's over 59.
- return computeSeconds(m[1], m[2], 0, m[4]);
- } else {
- // Timestamp takes the form of [minutes]:[seconds].[milliseconds]
- return computeSeconds(0, m[1], m[2], m[4]);
- }
- }
-
-// A settings object holds key/value pairs and will ignore anything but the first
-// assignment to a specific key.
- function Settings() {
- this.values = _objCreate(null);
- }
-
- Settings.prototype = {
- // Only accept the first assignment to any key.
- set: function(k, v) {
- if (!this.get(k) && v !== "") {
- this.values[k] = v;
- }
- },
- // Return the value for a key, or a default value.
- // If 'defaultKey' is passed then 'dflt' is assumed to be an object with
- // a number of possible default values as properties where 'defaultKey' is
- // the key of the property that will be chosen; otherwise it's assumed to be
- // a single value.
- get: function(k, dflt, defaultKey) {
- if (defaultKey) {
- return this.has(k) ? this.values[k] : dflt[defaultKey];
- }
- return this.has(k) ? this.values[k] : dflt;
- },
- // Check whether we have a value for a key.
- has: function(k) {
- return k in this.values;
- },
- // Accept a setting if its one of the given alternatives.
- alt: function(k, v, a) {
- for (var n = 0; n < a.length; ++n) {
- if (v === a[n]) {
- this.set(k, v);
- break;
- }
- }
- },
- // Accept a setting if its a valid (signed) integer.
- integer: function(k, v) {
- if (/^-?\d+$/.test(v)) { // integer
- this.set(k, parseInt(v, 10));
- }
- },
- // Accept a setting if its a valid percentage.
- percent: function(k, v) {
- var m;
- if ((m = v.match(/^([\d]{1,3})(\.[\d]*)?%$/))) {
- v = parseFloat(v);
- if (v >= 0 && v <= 100) {
- this.set(k, v);
- return true;
- }
- }
- return false;
- }
- };
-
-// Helper function to parse input into groups separated by 'groupDelim', and
-// interprete each group as a key/value pair separated by 'keyValueDelim'.
- function parseOptions(input, callback, keyValueDelim, groupDelim) {
- var groups = groupDelim ? input.split(groupDelim) : [input];
- for (var i in groups) {
- if (typeof groups[i] !== "string") {
- continue;
- }
- var kv = groups[i].split(keyValueDelim);
- if (kv.length !== 2) {
- continue;
- }
- var k = kv[0];
- var v = kv[1];
- callback(k, v);
- }
- }
-
- function parseCue(input, cue, regionList) {
- // Remember the original input if we need to throw an error.
- var oInput = input;
- // 4.1 WebVTT timestamp
- function consumeTimeStamp() {
- var ts = parseTimeStamp(input);
- if (ts === null) {
- throw new ParsingError(ParsingError.Errors.BadTimeStamp,
- "Malformed timestamp: " + oInput);
- }
- // Remove time stamp from input.
- input = input.replace(/^[^\sa-zA-Z-]+/, "");
- return ts;
- }
-
- // 4.4.2 WebVTT cue settings
- function consumeCueSettings(input, cue) {
- var settings = new Settings();
-
- parseOptions(input, function (k, v) {
- switch (k) {
- case "region":
- // Find the last region we parsed with the same region id.
- for (var i = regionList.length - 1; i >= 0; i--) {
- if (regionList[i].id === v) {
- settings.set(k, regionList[i].region);
- break;
- }
- }
- break;
- case "vertical":
- settings.alt(k, v, ["rl", "lr"]);
- break;
- case "line":
- var vals = v.split(","),
- vals0 = vals[0];
- settings.integer(k, vals0);
- settings.percent(k, vals0) ? settings.set("snapToLines", false) : null;
- settings.alt(k, vals0, ["auto"]);
- if (vals.length === 2) {
- settings.alt("lineAlign", vals[1], ["start", "middle", "end"]);
- }
- break;
- case "position":
- vals = v.split(",");
- settings.percent(k, vals[0]);
- if (vals.length === 2) {
- settings.alt("positionAlign", vals[1], ["start", "middle", "end"]);
- }
- break;
- case "size":
- settings.percent(k, v);
- break;
- case "align":
- settings.alt(k, v, ["start", "middle", "end", "left", "right"]);
- break;
- }
- }, /:/, /\s/);
-
- // Apply default values for any missing fields.
- cue.region = settings.get("region", null);
- cue.vertical = settings.get("vertical", "");
- cue.line = settings.get("line", "auto");
- cue.lineAlign = settings.get("lineAlign", "start");
- cue.snapToLines = settings.get("snapToLines", true);
- cue.size = settings.get("size", 100);
- cue.align = settings.get("align", "middle");
- cue.position = settings.get("position", {
- start: 0,
- left: 0,
- middle: 50,
- end: 100,
- right: 100
- }, cue.align);
- cue.positionAlign = settings.get("positionAlign", {
- start: "start",
- left: "start",
- middle: "middle",
- end: "end",
- right: "end"
- }, cue.align);
- }
-
- function skipWhitespace() {
- input = input.replace(/^\s+/, "");
- }
-
- // 4.1 WebVTT cue timings.
- skipWhitespace();
- cue.startTime = consumeTimeStamp(); // (1) collect cue start time
- skipWhitespace();
- if (input.substr(0, 3) !== "-->") { // (3) next characters must match "-->"
- throw new ParsingError(ParsingError.Errors.BadTimeStamp,
- "Malformed time stamp (time stamps must be separated by '-->'): " +
- oInput);
- }
- input = input.substr(3);
- skipWhitespace();
- cue.endTime = consumeTimeStamp(); // (5) collect cue end time
-
- // 4.1 WebVTT cue settings list.
- skipWhitespace();
- consumeCueSettings(input, cue);
- }
-
- var ESCAPE = {
- "&": "&",
- "<": "<",
- ">": ">",
- "": "\u200e",
- "": "\u200f",
- " ": "\u00a0"
- };
-
- var TAG_NAME = {
- c: "span",
- i: "i",
- b: "b",
- u: "u",
- ruby: "ruby",
- rt: "rt",
- v: "span",
- lang: "span"
- };
-
- var TAG_ANNOTATION = {
- v: "title",
- lang: "lang"
- };
-
- var NEEDS_PARENT = {
- rt: "ruby"
- };
-
-// Parse content into a document fragment.
- function parseContent(window, input) {
- function nextToken() {
- // Check for end-of-string.
- if (!input) {
- return null;
- }
-
- // Consume 'n' characters from the input.
- function consume(result) {
- input = input.substr(result.length);
- return result;
- }
-
- var m = input.match(/^([^<]*)(<[^>]+>?)?/);
- // If there is some text before the next tag, return it, otherwise return
- // the tag.
- return consume(m[1] ? m[1] : m[2]);
- }
-
- // Unescape a string 's'.
- function unescape1(e) {
- return ESCAPE[e];
- }
- function unescape(s) {
- while ((m = s.match(/&(amp|lt|gt|lrm|rlm|nbsp);/))) {
- s = s.replace(m[0], unescape1);
- }
- return s;
- }
-
- function shouldAdd(current, element) {
- return !NEEDS_PARENT[element.localName] ||
- NEEDS_PARENT[element.localName] === current.localName;
- }
-
- // Create an element for this tag.
- function createElement(type, annotation) {
- var tagName = TAG_NAME[type];
- if (!tagName) {
- return null;
- }
- var element = window.document.createElement(tagName);
- element.localName = tagName;
- var name = TAG_ANNOTATION[type];
- if (name && annotation) {
- element[name] = annotation.trim();
- }
- return element;
- }
-
- var rootDiv = window.document.createElement("div"),
- current = rootDiv,
- t,
- tagStack = [];
-
- while ((t = nextToken()) !== null) {
- if (t[0] === '<') {
- if (t[1] === "/") {
- // If the closing tag matches, move back up to the parent node.
- if (tagStack.length &&
- tagStack[tagStack.length - 1] === t.substr(2).replace(">", "")) {
- tagStack.pop();
- current = current.parentNode;
- }
- // Otherwise just ignore the end tag.
- continue;
- }
- var ts = parseTimeStamp(t.substr(1, t.length - 2));
- var node;
- if (ts) {
- // Timestamps are lead nodes as well.
- node = window.document.createProcessingInstruction("timestamp", ts);
- current.appendChild(node);
- continue;
- }
- var m = t.match(/^<([^.\s/0-9>]+)(\.[^\s\\>]+)?([^>\\]+)?(\\?)>?$/);
- // If we can't parse the tag, skip to the next tag.
- if (!m) {
- continue;
- }
- // Try to construct an element, and ignore the tag if we couldn't.
- node = createElement(m[1], m[3]);
- if (!node) {
- continue;
- }
- // Determine if the tag should be added based on the context of where it
- // is placed in the cuetext.
- if (!shouldAdd(current, node)) {
- continue;
- }
- // Set the class list (as a list of classes, separated by space).
- if (m[2]) {
- node.className = m[2].substr(1).replace('.', ' ');
- }
- // Append the node to the current node, and enter the scope of the new
- // node.
- tagStack.push(m[1]);
- current.appendChild(node);
- current = node;
- continue;
- }
-
- // Text nodes are leaf nodes.
- current.appendChild(window.document.createTextNode(unescape(t)));
- }
-
- return rootDiv;
- }
-
-// This is a list of all the Unicode characters that have a strong
-// right-to-left category. What this means is that these characters are
-// written right-to-left for sure. It was generated by pulling all the strong
-// right-to-left characters out of the Unicode data table. That table can
-// found at: http://www.unicode.org/Public/UNIDATA/UnicodeData.txt
- var strongRTLRanges = [[0x5be, 0x5be], [0x5c0, 0x5c0], [0x5c3, 0x5c3], [0x5c6, 0x5c6],
- [0x5d0, 0x5ea], [0x5f0, 0x5f4], [0x608, 0x608], [0x60b, 0x60b], [0x60d, 0x60d],
- [0x61b, 0x61b], [0x61e, 0x64a], [0x66d, 0x66f], [0x671, 0x6d5], [0x6e5, 0x6e6],
- [0x6ee, 0x6ef], [0x6fa, 0x70d], [0x70f, 0x710], [0x712, 0x72f], [0x74d, 0x7a5],
- [0x7b1, 0x7b1], [0x7c0, 0x7ea], [0x7f4, 0x7f5], [0x7fa, 0x7fa], [0x800, 0x815],
- [0x81a, 0x81a], [0x824, 0x824], [0x828, 0x828], [0x830, 0x83e], [0x840, 0x858],
- [0x85e, 0x85e], [0x8a0, 0x8a0], [0x8a2, 0x8ac], [0x200f, 0x200f],
- [0xfb1d, 0xfb1d], [0xfb1f, 0xfb28], [0xfb2a, 0xfb36], [0xfb38, 0xfb3c],
- [0xfb3e, 0xfb3e], [0xfb40, 0xfb41], [0xfb43, 0xfb44], [0xfb46, 0xfbc1],
- [0xfbd3, 0xfd3d], [0xfd50, 0xfd8f], [0xfd92, 0xfdc7], [0xfdf0, 0xfdfc],
- [0xfe70, 0xfe74], [0xfe76, 0xfefc], [0x10800, 0x10805], [0x10808, 0x10808],
- [0x1080a, 0x10835], [0x10837, 0x10838], [0x1083c, 0x1083c], [0x1083f, 0x10855],
- [0x10857, 0x1085f], [0x10900, 0x1091b], [0x10920, 0x10939], [0x1093f, 0x1093f],
- [0x10980, 0x109b7], [0x109be, 0x109bf], [0x10a00, 0x10a00], [0x10a10, 0x10a13],
- [0x10a15, 0x10a17], [0x10a19, 0x10a33], [0x10a40, 0x10a47], [0x10a50, 0x10a58],
- [0x10a60, 0x10a7f], [0x10b00, 0x10b35], [0x10b40, 0x10b55], [0x10b58, 0x10b72],
- [0x10b78, 0x10b7f], [0x10c00, 0x10c48], [0x1ee00, 0x1ee03], [0x1ee05, 0x1ee1f],
- [0x1ee21, 0x1ee22], [0x1ee24, 0x1ee24], [0x1ee27, 0x1ee27], [0x1ee29, 0x1ee32],
- [0x1ee34, 0x1ee37], [0x1ee39, 0x1ee39], [0x1ee3b, 0x1ee3b], [0x1ee42, 0x1ee42],
- [0x1ee47, 0x1ee47], [0x1ee49, 0x1ee49], [0x1ee4b, 0x1ee4b], [0x1ee4d, 0x1ee4f],
- [0x1ee51, 0x1ee52], [0x1ee54, 0x1ee54], [0x1ee57, 0x1ee57], [0x1ee59, 0x1ee59],
- [0x1ee5b, 0x1ee5b], [0x1ee5d, 0x1ee5d], [0x1ee5f, 0x1ee5f], [0x1ee61, 0x1ee62],
- [0x1ee64, 0x1ee64], [0x1ee67, 0x1ee6a], [0x1ee6c, 0x1ee72], [0x1ee74, 0x1ee77],
- [0x1ee79, 0x1ee7c], [0x1ee7e, 0x1ee7e], [0x1ee80, 0x1ee89], [0x1ee8b, 0x1ee9b],
- [0x1eea1, 0x1eea3], [0x1eea5, 0x1eea9], [0x1eeab, 0x1eebb], [0x10fffd, 0x10fffd]];
-
- function isStrongRTLChar(charCode) {
- for (var i = 0; i < strongRTLRanges.length; i++) {
- var currentRange = strongRTLRanges[i];
- if (charCode >= currentRange[0] && charCode <= currentRange[1]) {
- return true;
- }
- }
-
- return false;
- }
-
- function determineBidi(cueDiv) {
- var nodeStack = [],
- text = "",
- charCode;
-
- if (!cueDiv || !cueDiv.childNodes) {
- return "ltr";
- }
-
- function pushNodes(nodeStack, node) {
- for (var i = node.childNodes.length - 1; i >= 0; i--) {
- nodeStack.push(node.childNodes[i]);
- }
- }
-
- function nextTextNode(nodeStack) {
- if (!nodeStack || !nodeStack.length) {
- return null;
- }
-
- var node = nodeStack.pop(),
- text = node.textContent || node.innerText;
- if (text) {
- // TODO: This should match all unicode type B characters (paragraph
- // separator characters). See issue #115.
- var m = text.match(/^.*(\n|\r)/);
- if (m) {
- nodeStack.length = 0;
- return m[0];
- }
- return text;
- }
- if (node.tagName === "ruby") {
- return nextTextNode(nodeStack);
- }
- if (node.childNodes) {
- pushNodes(nodeStack, node);
- return nextTextNode(nodeStack);
- }
- }
-
- pushNodes(nodeStack, cueDiv);
- while ((text = nextTextNode(nodeStack))) {
- for (var i = 0; i < text.length; i++) {
- charCode = text.charCodeAt(i);
- if (isStrongRTLChar(charCode)) {
- return "rtl";
- }
- }
- }
- return "ltr";
- }
-
- function computeLinePos(cue) {
- if (typeof cue.line === "number" &&
- (cue.snapToLines || (cue.line >= 0 && cue.line <= 100))) {
- return cue.line;
- }
- if (!cue.track || !cue.track.textTrackList ||
- !cue.track.textTrackList.mediaElement) {
- return -1;
- }
- var track = cue.track,
- trackList = track.textTrackList,
- count = 0;
- for (var i = 0; i < trackList.length && trackList[i] !== track; i++) {
- if (trackList[i].mode === "showing") {
- count++;
- }
- }
- return ++count * -1;
- }
-
- function StyleBox() {
- }
-
-// Apply styles to a div. If there is no div passed then it defaults to the
-// div on 'this'.
- StyleBox.prototype.applyStyles = function(styles, div) {
- div = div || this.div;
- for (var prop in styles) {
- if (styles.hasOwnProperty(prop)) {
- div.style[prop] = styles[prop];
- }
- }
- };
-
- StyleBox.prototype.formatStyle = function(val, unit) {
- return val === 0 ? 0 : val + unit;
- };
-
-// Constructs the computed display state of the cue (a div). Places the div
-// into the overlay which should be a block level element (usually a div).
- function CueStyleBox(window, cue, styleOptions) {
- var isIE8 = (/MSIE\s8\.0/).test(navigator.userAgent);
- var color = "rgba(255, 255, 255, 1)";
- var backgroundColor = "rgba(0, 0, 0, 0.8)";
-
- if (isIE8) {
- color = "rgb(255, 255, 255)";
- backgroundColor = "rgb(0, 0, 0)";
- }
-
- StyleBox.call(this);
- this.cue = cue;
-
- // Parse our cue's text into a DOM tree rooted at 'cueDiv'. This div will
- // have inline positioning and will function as the cue background box.
- this.cueDiv = parseContent(window, cue.text);
- var styles = {
- color: color,
- backgroundColor: backgroundColor,
- position: "relative",
- left: 0,
- right: 0,
- top: 0,
- bottom: 0,
- display: "inline"
- };
-
- if (!isIE8) {
- styles.writingMode = cue.vertical === "" ? "horizontal-tb"
- : cue.vertical === "lr" ? "vertical-lr"
- : "vertical-rl";
- styles.unicodeBidi = "plaintext";
- }
- this.applyStyles(styles, this.cueDiv);
-
- // Create an absolutely positioned div that will be used to position the cue
- // div. Note, all WebVTT cue-setting alignments are equivalent to the CSS
- // mirrors of them except "middle" which is "center" in CSS.
- this.div = window.document.createElement("div");
- styles = {
- textAlign: cue.align === "middle" ? "center" : cue.align,
- font: styleOptions.font,
- whiteSpace: "pre-line",
- position: "absolute"
- };
-
- if (!isIE8) {
- styles.direction = determineBidi(this.cueDiv);
- styles.writingMode = cue.vertical === "" ? "horizontal-tb"
- : cue.vertical === "lr" ? "vertical-lr"
- : "vertical-rl".
- stylesunicodeBidi = "plaintext";
- }
-
- this.applyStyles(styles);
-
- this.div.appendChild(this.cueDiv);
-
- // Calculate the distance from the reference edge of the viewport to the text
- // position of the cue box. The reference edge will be resolved later when
- // the box orientation styles are applied.
- var textPos = 0;
- switch (cue.positionAlign) {
- case "start":
- textPos = cue.position;
- break;
- case "middle":
- textPos = cue.position - (cue.size / 2);
- break;
- case "end":
- textPos = cue.position - cue.size;
- break;
- }
-
- // Horizontal box orientation; textPos is the distance from the left edge of the
- // area to the left edge of the box and cue.size is the distance extending to
- // the right from there.
- if (cue.vertical === "") {
- this.applyStyles({
- left: this.formatStyle(textPos, "%"),
- width: this.formatStyle(cue.size, "%")
- });
- // Vertical box orientation; textPos is the distance from the top edge of the
- // area to the top edge of the box and cue.size is the height extending
- // downwards from there.
- } else {
- this.applyStyles({
- top: this.formatStyle(textPos, "%"),
- height: this.formatStyle(cue.size, "%")
- });
- }
-
- this.move = function(box) {
- this.applyStyles({
- top: this.formatStyle(box.top, "px"),
- bottom: this.formatStyle(box.bottom, "px"),
- left: this.formatStyle(box.left, "px"),
- right: this.formatStyle(box.right, "px"),
- height: this.formatStyle(box.height, "px"),
- width: this.formatStyle(box.width, "px")
- });
- };
- }
- CueStyleBox.prototype = _objCreate(StyleBox.prototype);
- CueStyleBox.prototype.constructor = CueStyleBox;
-
-// Represents the co-ordinates of an Element in a way that we can easily
-// compute things with such as if it overlaps or intersects with another Element.
-// Can initialize it with either a StyleBox or another BoxPosition.
- function BoxPosition(obj) {
- var isIE8 = (/MSIE\s8\.0/).test(navigator.userAgent);
-
- // Either a BoxPosition was passed in and we need to copy it, or a StyleBox
- // was passed in and we need to copy the results of 'getBoundingClientRect'
- // as the object returned is readonly. All co-ordinate values are in reference
- // to the viewport origin (top left).
- var lh, height, width, top;
- if (obj.div) {
- height = obj.div.offsetHeight;
- width = obj.div.offsetWidth;
- top = obj.div.offsetTop;
-
- var rects = (rects = obj.div.childNodes) && (rects = rects[0]) &&
- rects.getClientRects && rects.getClientRects();
- obj = obj.div.getBoundingClientRect();
- // In certain cases the outter div will be slightly larger then the sum of
- // the inner div's lines. This could be due to bold text, etc, on some platforms.
- // In this case we should get the average line height and use that. This will
- // result in the desired behaviour.
- lh = rects ? Math.max((rects[0] && rects[0].height) || 0, obj.height / rects.length)
- : 0;
-
- }
- this.left = obj.left;
- this.right = obj.right;
- this.top = obj.top || top;
- this.height = obj.height || height;
- this.bottom = obj.bottom || (top + (obj.height || height));
- this.width = obj.width || width;
- this.lineHeight = lh !== undefined ? lh : obj.lineHeight;
-
- if (isIE8 && !this.lineHeight) {
- this.lineHeight = 13;
- }
- }
-
-// Move the box along a particular axis. Optionally pass in an amount to move
-// the box. If no amount is passed then the default is the line height of the
-// box.
- BoxPosition.prototype.move = function(axis, toMove) {
- toMove = toMove !== undefined ? toMove : this.lineHeight;
- switch (axis) {
- case "+x":
- this.left += toMove;
- this.right += toMove;
- break;
- case "-x":
- this.left -= toMove;
- this.right -= toMove;
- break;
- case "+y":
- this.top += toMove;
- this.bottom += toMove;
- break;
- case "-y":
- this.top -= toMove;
- this.bottom -= toMove;
- break;
- }
- };
-
-// Check if this box overlaps another box, b2.
- BoxPosition.prototype.overlaps = function(b2) {
- return this.left < b2.right &&
- this.right > b2.left &&
- this.top < b2.bottom &&
- this.bottom > b2.top;
- };
-
-// Check if this box overlaps any other boxes in boxes.
- BoxPosition.prototype.overlapsAny = function(boxes) {
- for (var i = 0; i < boxes.length; i++) {
- if (this.overlaps(boxes[i])) {
- return true;
- }
- }
- return false;
- };
-
-// Check if this box is within another box.
- BoxPosition.prototype.within = function(container) {
- return this.top >= container.top &&
- this.bottom <= container.bottom &&
- this.left >= container.left &&
- this.right <= container.right;
- };
-
-// Check if this box is entirely within the container or it is overlapping
-// on the edge opposite of the axis direction passed. For example, if "+x" is
-// passed and the box is overlapping on the left edge of the container, then
-// return true.
- BoxPosition.prototype.overlapsOppositeAxis = function(container, axis) {
- switch (axis) {
- case "+x":
- return this.left < container.left;
- case "-x":
- return this.right > container.right;
- case "+y":
- return this.top < container.top;
- case "-y":
- return this.bottom > container.bottom;
- }
- };
-
-// Find the percentage of the area that this box is overlapping with another
-// box.
- BoxPosition.prototype.intersectPercentage = function(b2) {
- var x = Math.max(0, Math.min(this.right, b2.right) - Math.max(this.left, b2.left)),
- y = Math.max(0, Math.min(this.bottom, b2.bottom) - Math.max(this.top, b2.top)),
- intersectArea = x * y;
- return intersectArea / (this.height * this.width);
- };
-
-// Convert the positions from this box to CSS compatible positions using
-// the reference container's positions. This has to be done because this
-// box's positions are in reference to the viewport origin, whereas, CSS
-// values are in referecne to their respective edges.
- BoxPosition.prototype.toCSSCompatValues = function(reference) {
- return {
- top: this.top - reference.top,
- bottom: reference.bottom - this.bottom,
- left: this.left - reference.left,
- right: reference.right - this.right,
- height: this.height,
- width: this.width
- };
- };
-
-// Get an object that represents the box's position without anything extra.
-// Can pass a StyleBox, HTMLElement, or another BoxPositon.
- BoxPosition.getSimpleBoxPosition = function(obj) {
- var height = obj.div ? obj.div.offsetHeight : obj.tagName ? obj.offsetHeight : 0;
- var width = obj.div ? obj.div.offsetWidth : obj.tagName ? obj.offsetWidth : 0;
- var top = obj.div ? obj.div.offsetTop : obj.tagName ? obj.offsetTop : 0;
-
- obj = obj.div ? obj.div.getBoundingClientRect() :
- obj.tagName ? obj.getBoundingClientRect() : obj;
- var ret = {
- left: obj.left,
- right: obj.right,
- top: obj.top || top,
- height: obj.height || height,
- bottom: obj.bottom || (top + (obj.height || height)),
- width: obj.width || width
- };
- return ret;
- };
-
-// Move a StyleBox to its specified, or next best, position. The containerBox
-// is the box that contains the StyleBox, such as a div. boxPositions are
-// a list of other boxes that the styleBox can't overlap with.
- function moveBoxToLinePosition(window, styleBox, containerBox, boxPositions) {
-
- // Find the best position for a cue box, b, on the video. The axis parameter
- // is a list of axis, the order of which, it will move the box along. For example:
- // Passing ["+x", "-x"] will move the box first along the x axis in the positive
- // direction. If it doesn't find a good position for it there it will then move
- // it along the x axis in the negative direction.
- function findBestPosition(b, axis) {
- var bestPosition,
- specifiedPosition = new BoxPosition(b),
- percentage = 1; // Highest possible so the first thing we get is better.
-
- for (var i = 0; i < axis.length; i++) {
- while (b.overlapsOppositeAxis(containerBox, axis[i]) ||
- (b.within(containerBox) && b.overlapsAny(boxPositions))) {
- b.move(axis[i]);
- }
- // We found a spot where we aren't overlapping anything. This is our
- // best position.
- if (b.within(containerBox)) {
- return b;
- }
- var p = b.intersectPercentage(containerBox);
- // If we're outside the container box less then we were on our last try
- // then remember this position as the best position.
- if (percentage > p) {
- bestPosition = new BoxPosition(b);
- percentage = p;
- }
- // Reset the box position to the specified position.
- b = new BoxPosition(specifiedPosition);
- }
- return bestPosition || specifiedPosition;
- }
-
- var boxPosition = new BoxPosition(styleBox),
- cue = styleBox.cue,
- linePos = computeLinePos(cue),
- axis = [];
-
- // If we have a line number to align the cue to.
- if (cue.snapToLines) {
- var size;
- switch (cue.vertical) {
- case "":
- axis = [ "+y", "-y" ];
- size = "height";
- break;
- case "rl":
- axis = [ "+x", "-x" ];
- size = "width";
- break;
- case "lr":
- axis = [ "-x", "+x" ];
- size = "width";
- break;
- }
-
- var step = boxPosition.lineHeight,
- position = step * Math.round(linePos),
- maxPosition = containerBox[size] + step,
- initialAxis = axis[0];
-
- // If the specified intial position is greater then the max position then
- // clamp the box to the amount of steps it would take for the box to
- // reach the max position.
- if (Math.abs(position) > maxPosition) {
- position = position < 0 ? -1 : 1;
- position *= Math.ceil(maxPosition / step) * step;
- }
-
- // If computed line position returns negative then line numbers are
- // relative to the bottom of the video instead of the top. Therefore, we
- // need to increase our initial position by the length or width of the
- // video, depending on the writing direction, and reverse our axis directions.
- if (linePos < 0) {
- position += cue.vertical === "" ? containerBox.height : containerBox.width;
- axis = axis.reverse();
- }
-
- // Move the box to the specified position. This may not be its best
- // position.
- boxPosition.move(initialAxis, position);
-
- } else {
- // If we have a percentage line value for the cue.
- var calculatedPercentage = (boxPosition.lineHeight / containerBox.height) * 100;
-
- switch (cue.lineAlign) {
- case "middle":
- linePos -= (calculatedPercentage / 2);
- break;
- case "end":
- linePos -= calculatedPercentage;
- break;
- }
-
- // Apply initial line position to the cue box.
- switch (cue.vertical) {
- case "":
- styleBox.applyStyles({
- top: styleBox.formatStyle(linePos, "%")
- });
- break;
- case "rl":
- styleBox.applyStyles({
- left: styleBox.formatStyle(linePos, "%")
- });
- break;
- case "lr":
- styleBox.applyStyles({
- right: styleBox.formatStyle(linePos, "%")
- });
- break;
- }
-
- axis = [ "+y", "-x", "+x", "-y" ];
-
- // Get the box position again after we've applied the specified positioning
- // to it.
- boxPosition = new BoxPosition(styleBox);
- }
-
- var bestPosition = findBestPosition(boxPosition, axis);
- styleBox.move(bestPosition.toCSSCompatValues(containerBox));
- }
-
- function WebVTT$1() {
- // Nothing
- }
-
-// Helper to allow strings to be decoded instead of the default binary utf8 data.
- WebVTT$1.StringDecoder = function() {
- return {
- decode: function(data) {
- if (!data) {
- return "";
- }
- if (typeof data !== "string") {
- throw new Error("Error - expected string data.");
- }
- return decodeURIComponent(encodeURIComponent(data));
- }
- };
- };
-
- WebVTT$1.convertCueToDOMTree = function(window, cuetext) {
- if (!window || !cuetext) {
- return null;
- }
- return parseContent(window, cuetext);
- };
-
- var FONT_SIZE_PERCENT = 0.05;
- var FONT_STYLE = "sans-serif";
- var CUE_BACKGROUND_PADDING = "1.5%";
-
-// Runs the processing model over the cues and regions passed to it.
-// @param overlay A block level element (usually a div) that the computed cues
-// and regions will be placed into.
- WebVTT$1.processCues = function(window, cues, overlay) {
- if (!window || !cues || !overlay) {
- return null;
- }
-
- // Remove all previous children.
- while (overlay.firstChild) {
- overlay.removeChild(overlay.firstChild);
- }
-
- var paddedOverlay = window.document.createElement("div");
- paddedOverlay.style.position = "absolute";
- paddedOverlay.style.left = "0";
- paddedOverlay.style.right = "0";
- paddedOverlay.style.top = "0";
- paddedOverlay.style.bottom = "0";
- paddedOverlay.style.margin = CUE_BACKGROUND_PADDING;
- overlay.appendChild(paddedOverlay);
-
- // Determine if we need to compute the display states of the cues. This could
- // be the case if a cue's state has been changed since the last computation or
- // if it has not been computed yet.
- function shouldCompute(cues) {
- for (var i = 0; i < cues.length; i++) {
- if (cues[i].hasBeenReset || !cues[i].displayState) {
- return true;
- }
- }
- return false;
- }
-
- // We don't need to recompute the cues' display states. Just reuse them.
- if (!shouldCompute(cues)) {
- for (var i = 0; i < cues.length; i++) {
- paddedOverlay.appendChild(cues[i].displayState);
- }
- return;
- }
-
- var boxPositions = [],
- containerBox = BoxPosition.getSimpleBoxPosition(paddedOverlay),
- fontSize = Math.round(containerBox.height * FONT_SIZE_PERCENT * 100) / 100;
- var styleOptions = {
- font: fontSize + "px " + FONT_STYLE
- };
-
- (function() {
- var styleBox, cue;
-
- for (var i = 0; i < cues.length; i++) {
- cue = cues[i];
-
- // Compute the intial position and styles of the cue div.
- styleBox = new CueStyleBox(window, cue, styleOptions);
- paddedOverlay.appendChild(styleBox.div);
-
- // Move the cue div to it's correct line position.
- moveBoxToLinePosition(window, styleBox, containerBox, boxPositions);
-
- // Remember the computed div so that we don't have to recompute it later
- // if we don't have too.
- cue.displayState = styleBox.div;
-
- boxPositions.push(BoxPosition.getSimpleBoxPosition(styleBox));
- }
- })();
- };
-
- WebVTT$1.Parser = function(window, vttjs, decoder) {
- if (!decoder) {
- decoder = vttjs;
- vttjs = {};
- }
- if (!vttjs) {
- vttjs = {};
- }
-
- this.window = window;
- this.vttjs = vttjs;
- this.state = "INITIAL";
- this.buffer = "";
- this.decoder = decoder || new TextDecoder("utf8");
- this.regionList = [];
- };
-
- WebVTT$1.Parser.prototype = {
- // If the error is a ParsingError then report it to the consumer if
- // possible. If it's not a ParsingError then throw it like normal.
- reportOrThrowError: function(e) {
- if (e instanceof ParsingError) {
- this.onparsingerror && this.onparsingerror(e);
- } else {
- throw e;
- }
- },
- parse: function (data) {
- var self = this;
-
- // If there is no data then we won't decode it, but will just try to parse
- // whatever is in buffer already. This may occur in circumstances, for
- // example when flush() is called.
- if (data) {
- // Try to decode the data that we received.
- self.buffer += self.decoder.decode(data, {stream: true});
- }
-
- function collectNextLine() {
- var buffer = self.buffer;
- var pos = 0;
- while (pos < buffer.length && buffer[pos] !== '\r' && buffer[pos] !== '\n') {
- ++pos;
- }
- var line = buffer.substr(0, pos);
- // Advance the buffer early in case we fail below.
- if (buffer[pos] === '\r') {
- ++pos;
- }
- if (buffer[pos] === '\n') {
- ++pos;
- }
- self.buffer = buffer.substr(pos);
- return line;
- }
-
- // 3.4 WebVTT region and WebVTT region settings syntax
- function parseRegion(input) {
- var settings = new Settings();
-
- parseOptions(input, function (k, v) {
- switch (k) {
- case "id":
- settings.set(k, v);
- break;
- case "width":
- settings.percent(k, v);
- break;
- case "lines":
- settings.integer(k, v);
- break;
- case "regionanchor":
- case "viewportanchor":
- var xy = v.split(',');
- if (xy.length !== 2) {
- break;
- }
- // We have to make sure both x and y parse, so use a temporary
- // settings object here.
- var anchor = new Settings();
- anchor.percent("x", xy[0]);
- anchor.percent("y", xy[1]);
- if (!anchor.has("x") || !anchor.has("y")) {
- break;
- }
- settings.set(k + "X", anchor.get("x"));
- settings.set(k + "Y", anchor.get("y"));
- break;
- case "scroll":
- settings.alt(k, v, ["up"]);
- break;
- }
- }, /=/, /\s/);
-
- // Create the region, using default values for any values that were not
- // specified.
- if (settings.has("id")) {
- var region = new (self.vttjs.VTTRegion || self.window.VTTRegion)();
- region.width = settings.get("width", 100);
- region.lines = settings.get("lines", 3);
- region.regionAnchorX = settings.get("regionanchorX", 0);
- region.regionAnchorY = settings.get("regionanchorY", 100);
- region.viewportAnchorX = settings.get("viewportanchorX", 0);
- region.viewportAnchorY = settings.get("viewportanchorY", 100);
- region.scroll = settings.get("scroll", "");
- // Register the region.
- self.onregion && self.onregion(region);
- // Remember the VTTRegion for later in case we parse any VTTCues that
- // reference it.
- self.regionList.push({
- id: settings.get("id"),
- region: region
- });
- }
- }
-
- // draft-pantos-http-live-streaming-20
- // https://tools.ietf.org/html/draft-pantos-http-live-streaming-20#section-3.5
- // 3.5 WebVTT
- function parseTimestampMap(input) {
- var settings = new Settings();
-
- parseOptions(input, function(k, v) {
- switch(k) {
- case "MPEGT":
- settings.integer(k + 'S', v);
- break;
- case "LOCA":
- settings.set(k + 'L', parseTimeStamp(v));
- break;
- }
- }, /[^\d]:/, /,/);
-
- self.ontimestampmap && self.ontimestampmap({
- "MPEGTS": settings.get("MPEGTS"),
- "LOCAL": settings.get("LOCAL")
- });
- }
-
- // 3.2 WebVTT metadata header syntax
- function parseHeader(input) {
- if (input.match(/X-TIMESTAMP-MAP/)) {
- // This line contains HLS X-TIMESTAMP-MAP metadata
- parseOptions(input, function(k, v) {
- switch(k) {
- case "X-TIMESTAMP-MAP":
- parseTimestampMap(v);
- break;
- }
- }, /=/);
- } else {
- parseOptions(input, function (k, v) {
- switch (k) {
- case "Region":
- // 3.3 WebVTT region metadata header syntax
- parseRegion(v);
- break;
- }
- }, /:/);
- }
-
- }
-
- // 5.1 WebVTT file parsing.
- try {
- var line;
- if (self.state === "INITIAL") {
- // We can't start parsing until we have the first line.
- if (!/\r\n|\n/.test(self.buffer)) {
- return this;
- }
-
- line = collectNextLine();
-
- var m = line.match(/^WEBVTT([ \t].*)?$/);
- if (!m || !m[0]) {
- throw new ParsingError(ParsingError.Errors.BadSignature);
- }
-
- self.state = "HEADER";
- }
-
- var alreadyCollectedLine = false;
- while (self.buffer) {
- // We can't parse a line until we have the full line.
- if (!/\r\n|\n/.test(self.buffer)) {
- return this;
- }
-
- if (!alreadyCollectedLine) {
- line = collectNextLine();
- } else {
- alreadyCollectedLine = false;
- }
-
- switch (self.state) {
- case "HEADER":
- // 13-18 - Allow a header (metadata) under the WEBVTT line.
- if (/:/.test(line)) {
- parseHeader(line);
- } else if (!line) {
- // An empty line terminates the header and starts the body (cues).
- self.state = "ID";
- }
- continue;
- case "NOTE":
- // Ignore NOTE blocks.
- if (!line) {
- self.state = "ID";
- }
- continue;
- case "ID":
- // Check for the start of NOTE blocks.
- if (/^NOTE($|[ \t])/.test(line)) {
- self.state = "NOTE";
- break;
- }
- // 19-29 - Allow any number of line terminators, then initialize new cue values.
- if (!line) {
- continue;
- }
- self.cue = new (self.vttjs.VTTCue || self.window.VTTCue)(0, 0, "");
- self.state = "CUE";
- // 30-39 - Check if self line contains an optional identifier or timing data.
- if (line.indexOf("-->") === -1) {
- self.cue.id = line;
- continue;
- }
- // Process line as start of a cue.
- /*falls through*/
- case "CUE":
- // 40 - Collect cue timings and settings.
- try {
- parseCue(line, self.cue, self.regionList);
- } catch (e) {
- self.reportOrThrowError(e);
- // In case of an error ignore rest of the cue.
- self.cue = null;
- self.state = "BADCUE";
- continue;
- }
- self.state = "CUETEXT";
- continue;
- case "CUETEXT":
- var hasSubstring = line.indexOf("-->") !== -1;
- // 34 - If we have an empty line then report the cue.
- // 35 - If we have the special substring '-->' then report the cue,
- // but do not collect the line as we need to process the current
- // one as a new cue.
- if (!line || hasSubstring && (alreadyCollectedLine = true)) {
- // We are done parsing self cue.
- self.oncue && self.oncue(self.cue);
- self.cue = null;
- self.state = "ID";
- continue;
- }
- if (self.cue.text) {
- self.cue.text += "\n";
- }
- self.cue.text += line;
- continue;
- case "BADCUE": // BADCUE
- // 54-62 - Collect and discard the remaining cue.
- if (!line) {
- self.state = "ID";
- }
- continue;
- }
- }
- } catch (e) {
- self.reportOrThrowError(e);
-
- // If we are currently parsing a cue, report what we have.
- if (self.state === "CUETEXT" && self.cue && self.oncue) {
- self.oncue(self.cue);
- }
- self.cue = null;
- // Enter BADWEBVTT state if header was not parsed correctly otherwise
- // another exception occurred so enter BADCUE state.
- self.state = self.state === "INITIAL" ? "BADWEBVTT" : "BADCUE";
- }
- return this;
- },
- flush: function () {
- var self = this;
- try {
- // Finish decoding the stream.
- self.buffer += self.decoder.decode();
- // Synthesize the end of the current cue or region.
- if (self.cue || self.state === "HEADER") {
- self.buffer += "\n\n";
- self.parse();
- }
- // If we've flushed, parsed, and we're still on the INITIAL state then
- // that means we don't have enough of the stream to parse the first
- // line.
- if (self.state === "INITIAL") {
- throw new ParsingError(ParsingError.Errors.BadSignature);
- }
- } catch(e) {
- self.reportOrThrowError(e);
- }
- self.onflush && self.onflush();
- return this;
- }
- };
-
- var vtt$1 = WebVTT$1;
-
- /**
- * Copyright 2013 vtt.js Contributors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- var autoKeyword = "auto";
- var directionSetting = {
- "": true,
- "lr": true,
- "rl": true
- };
- var alignSetting = {
- "start": true,
- "middle": true,
- "end": true,
- "left": true,
- "right": true
- };
-
- function findDirectionSetting(value) {
- if (typeof value !== "string") {
- return false;
- }
- var dir = directionSetting[value.toLowerCase()];
- return dir ? value.toLowerCase() : false;
- }
-
- function findAlignSetting(value) {
- if (typeof value !== "string") {
- return false;
- }
- var align = alignSetting[value.toLowerCase()];
- return align ? value.toLowerCase() : false;
- }
-
- function extend$1(obj) {
- var i = 1;
- for (; i < arguments.length; i++) {
- var cobj = arguments[i];
- for (var p in cobj) {
- obj[p] = cobj[p];
- }
- }
-
- return obj;
- }
-
- function VTTCue(startTime, endTime, text) {
- var cue = this;
- var isIE8 = (/MSIE\s8\.0/).test(navigator.userAgent);
- var baseObj = {};
-
- if (isIE8) {
- cue = document.createElement('custom');
- } else {
- baseObj.enumerable = true;
- }
-
- /**
- * Shim implementation specific properties. These properties are not in
- * the spec.
- */
-
- // Lets us know when the VTTCue's data has changed in such a way that we need
- // to recompute its display state. This lets us compute its display state
- // lazily.
- cue.hasBeenReset = false;
-
- /**
- * VTTCue and TextTrackCue properties
- * http://dev.w3.org/html5/webvtt/#vttcue-interface
- */
-
- var _id = "";
- var _pauseOnExit = false;
- var _startTime = startTime;
- var _endTime = endTime;
- var _text = text;
- var _region = null;
- var _vertical = "";
- var _snapToLines = true;
- var _line = "auto";
- var _lineAlign = "start";
- var _position = 50;
- var _positionAlign = "middle";
- var _size = 50;
- var _align = "middle";
-
- Object.defineProperty(cue,
- "id", extend$1({}, baseObj, {
- get: function() {
- return _id;
- },
- set: function(value) {
- _id = "" + value;
- }
- }));
-
- Object.defineProperty(cue,
- "pauseOnExit", extend$1({}, baseObj, {
- get: function() {
- return _pauseOnExit;
- },
- set: function(value) {
- _pauseOnExit = !!value;
- }
- }));
-
- Object.defineProperty(cue,
- "startTime", extend$1({}, baseObj, {
- get: function() {
- return _startTime;
- },
- set: function(value) {
- if (typeof value !== "number") {
- throw new TypeError("Start time must be set to a number.");
- }
- _startTime = value;
- this.hasBeenReset = true;
- }
- }));
-
- Object.defineProperty(cue,
- "endTime", extend$1({}, baseObj, {
- get: function() {
- return _endTime;
- },
- set: function(value) {
- if (typeof value !== "number") {
- throw new TypeError("End time must be set to a number.");
- }
- _endTime = value;
- this.hasBeenReset = true;
- }
- }));
-
- Object.defineProperty(cue,
- "text", extend$1({}, baseObj, {
- get: function() {
- return _text;
- },
- set: function(value) {
- _text = "" + value;
- this.hasBeenReset = true;
- }
- }));
-
- Object.defineProperty(cue,
- "region", extend$1({}, baseObj, {
- get: function() {
- return _region;
- },
- set: function(value) {
- _region = value;
- this.hasBeenReset = true;
- }
- }));
-
- Object.defineProperty(cue,
- "vertical", extend$1({}, baseObj, {
- get: function() {
- return _vertical;
- },
- set: function(value) {
- var setting = findDirectionSetting(value);
- // Have to check for false because the setting an be an empty string.
- if (setting === false) {
- throw new SyntaxError("An invalid or illegal string was specified.");
- }
- _vertical = setting;
- this.hasBeenReset = true;
- }
- }));
-
- Object.defineProperty(cue,
- "snapToLines", extend$1({}, baseObj, {
- get: function() {
- return _snapToLines;
- },
- set: function(value) {
- _snapToLines = !!value;
- this.hasBeenReset = true;
- }
- }));
-
- Object.defineProperty(cue,
- "line", extend$1({}, baseObj, {
- get: function() {
- return _line;
- },
- set: function(value) {
- if (typeof value !== "number" && value !== autoKeyword) {
- throw new SyntaxError("An invalid number or illegal string was specified.");
- }
- _line = value;
- this.hasBeenReset = true;
- }
- }));
-
- Object.defineProperty(cue,
- "lineAlign", extend$1({}, baseObj, {
- get: function() {
- return _lineAlign;
- },
- set: function(value) {
- var setting = findAlignSetting(value);
- if (!setting) {
- throw new SyntaxError("An invalid or illegal string was specified.");
- }
- _lineAlign = setting;
- this.hasBeenReset = true;
- }
- }));
-
- Object.defineProperty(cue,
- "position", extend$1({}, baseObj, {
- get: function() {
- return _position;
- },
- set: function(value) {
- if (value < 0 || value > 100) {
- throw new Error("Position must be between 0 and 100.");
- }
- _position = value;
- this.hasBeenReset = true;
- }
- }));
-
- Object.defineProperty(cue,
- "positionAlign", extend$1({}, baseObj, {
- get: function() {
- return _positionAlign;
- },
- set: function(value) {
- var setting = findAlignSetting(value);
- if (!setting) {
- throw new SyntaxError("An invalid or illegal string was specified.");
- }
- _positionAlign = setting;
- this.hasBeenReset = true;
- }
- }));
-
- Object.defineProperty(cue,
- "size", extend$1({}, baseObj, {
- get: function() {
- return _size;
- },
- set: function(value) {
- if (value < 0 || value > 100) {
- throw new Error("Size must be between 0 and 100.");
- }
- _size = value;
- this.hasBeenReset = true;
- }
- }));
-
- Object.defineProperty(cue,
- "align", extend$1({}, baseObj, {
- get: function() {
- return _align;
- },
- set: function(value) {
- var setting = findAlignSetting(value);
- if (!setting) {
- throw new SyntaxError("An invalid or illegal string was specified.");
- }
- _align = setting;
- this.hasBeenReset = true;
- }
- }));
-
- /**
- * Other