MDL-68216 block_recent_activity: Format elements more nicely.
[moodle.git] / media / player / videojs / amd / src / video-lazy.js
1 /**
2  * @license
3  * Video.js 7.6.5 <http://videojs.com/>
4  * Copyright Brightcove, Inc. <https://www.brightcove.com/>
5  * Available under Apache License Version 2.0
6  * <https://github.com/videojs/video.js/blob/master/LICENSE>
7  *
8  * Includes vtt.js <https://github.com/mozilla/vtt.js>
9  * Available under Apache License Version 2.0
10  * <https://github.com/mozilla/vtt.js/blob/master/LICENSE>
11  */
13 (function (global, factory) {
14   typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('global/window'), require('global/document')) :
15   typeof define === 'function' && define.amd ? define(['./window', './document'], factory) :
16   (global = global || self, global.videojs = factory(global.window, global.document));
17 }(this, function (window$1, document) {
18   window$1 = window$1 && window$1.hasOwnProperty('default') ? window$1['default'] : window$1;
19   document = document && document.hasOwnProperty('default') ? document['default'] : document;
21   var version = "7.6.5";
23   /**
24    * @file create-logger.js
25    * @module create-logger
26    */
28   var history = [];
29   /**
30    * Log messages to the console and history based on the type of message
31    *
32    * @private
33    * @param  {string} type
34    *         The name of the console method to use.
35    *
36    * @param  {Array} args
37    *         The arguments to be passed to the matching console method.
38    */
40   var LogByTypeFactory = function LogByTypeFactory(name, log) {
41     return function (type, level, args) {
42       var lvl = log.levels[level];
43       var lvlRegExp = new RegExp("^(" + lvl + ")$");
45       if (type !== 'log') {
46         // Add the type to the front of the message when it's not "log".
47         args.unshift(type.toUpperCase() + ':');
48       } // Add console prefix after adding to history.
51       args.unshift(name + ':'); // Add a clone of the args at this point to history.
53       if (history) {
54         history.push([].concat(args));
55       } // If there's no console then don't try to output messages, but they will
56       // still be stored in history.
59       if (!window$1.console) {
60         return;
61       } // Was setting these once outside of this function, but containing them
62       // in the function makes it easier to test cases where console doesn't exist
63       // when the module is executed.
66       var fn = window$1.console[type];
68       if (!fn && type === 'debug') {
69         // Certain browsers don't have support for console.debug. For those, we
70         // should default to the closest comparable log.
71         fn = window$1.console.info || window$1.console.log;
72       } // Bail out if there's no console or if this type is not allowed by the
73       // current logging level.
76       if (!fn || !lvl || !lvlRegExp.test(type)) {
77         return;
78       }
80       fn[Array.isArray(args) ? 'apply' : 'call'](window$1.console, args);
81     };
82   };
84   function createLogger(name) {
85     // This is the private tracking variable for logging level.
86     var level = 'info'; // the curried logByType bound to the specific log and history
88     var logByType;
89     /**
90      * Logs plain debug messages. Similar to `console.log`.
91      *
92      * Due to [limitations](https://github.com/jsdoc3/jsdoc/issues/955#issuecomment-313829149)
93      * of our JSDoc template, we cannot properly document this as both a function
94      * and a namespace, so its function signature is documented here.
95      *
96      * #### Arguments
97      * ##### *args
98      * Mixed[]
99      *
100      * Any combination of values that could be passed to `console.log()`.
101      *
102      * #### Return Value
103      *
104      * `undefined`
105      *
106      * @namespace
107      * @param    {Mixed[]} args
108      *           One or more messages or objects that should be logged.
109      */
111     var log = function log() {
112       for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
113         args[_key] = arguments[_key];
114       }
116       logByType('log', level, args);
117     }; // This is the logByType helper that the logging methods below use
120     logByType = LogByTypeFactory(name, log);
121     /**
122      * Create a new sublogger which chains the old name to the new name.
123      *
124      * For example, doing `videojs.log.createLogger('player')` and then using that logger will log the following:
125      * ```js
126      *  mylogger('foo');
127      *  // > VIDEOJS: player: foo
128      * ```
129      *
130      * @param {string} name
131      *        The name to add call the new logger
132      * @return {Object}
133      */
135     log.createLogger = function (subname) {
136       return createLogger(name + ': ' + subname);
137     };
138     /**
139      * Enumeration of available logging levels, where the keys are the level names
140      * and the values are `|`-separated strings containing logging methods allowed
141      * in that logging level. These strings are used to create a regular expression
142      * matching the function name being called.
143      *
144      * Levels provided by Video.js are:
145      *
146      * - `off`: Matches no calls. Any value that can be cast to `false` will have
147      *   this effect. The most restrictive.
148      * - `all`: Matches only Video.js-provided functions (`debug`, `log`,
149      *   `log.warn`, and `log.error`).
150      * - `debug`: Matches `log.debug`, `log`, `log.warn`, and `log.error` calls.
151      * - `info` (default): Matches `log`, `log.warn`, and `log.error` calls.
152      * - `warn`: Matches `log.warn` and `log.error` calls.
153      * - `error`: Matches only `log.error` calls.
154      *
155      * @type {Object}
156      */
159     log.levels = {
160       all: 'debug|log|warn|error',
161       off: '',
162       debug: 'debug|log|warn|error',
163       info: 'log|warn|error',
164       warn: 'warn|error',
165       error: 'error',
166       DEFAULT: level
167     };
168     /**
169      * Get or set the current logging level.
170      *
171      * If a string matching a key from {@link module:log.levels} is provided, acts
172      * as a setter.
173      *
174      * @param  {string} [lvl]
175      *         Pass a valid level to set a new logging level.
176      *
177      * @return {string}
178      *         The current logging level.
179      */
181     log.level = function (lvl) {
182       if (typeof lvl === 'string') {
183         if (!log.levels.hasOwnProperty(lvl)) {
184           throw new Error("\"" + lvl + "\" in not a valid log level");
185         }
187         level = lvl;
188       }
190       return level;
191     };
192     /**
193      * Returns an array containing everything that has been logged to the history.
194      *
195      * This array is a shallow clone of the internal history record. However, its
196      * contents are _not_ cloned; so, mutating objects inside this array will
197      * mutate them in history.
198      *
199      * @return {Array}
200      */
203     log.history = function () {
204       return history ? [].concat(history) : [];
205     };
206     /**
207      * Allows you to filter the history by the given logger name
208      *
209      * @param {string} fname
210      *        The name to filter by
211      *
212      * @return {Array}
213      *         The filtered list to return
214      */
217     log.history.filter = function (fname) {
218       return (history || []).filter(function (historyItem) {
219         // if the first item in each historyItem includes `fname`, then it's a match
220         return new RegExp(".*" + fname + ".*").test(historyItem[0]);
221       });
222     };
223     /**
224      * Clears the internal history tracking, but does not prevent further history
225      * tracking.
226      */
229     log.history.clear = function () {
230       if (history) {
231         history.length = 0;
232       }
233     };
234     /**
235      * Disable history tracking if it is currently enabled.
236      */
239     log.history.disable = function () {
240       if (history !== null) {
241         history.length = 0;
242         history = null;
243       }
244     };
245     /**
246      * Enable history tracking if it is currently disabled.
247      */
250     log.history.enable = function () {
251       if (history === null) {
252         history = [];
253       }
254     };
255     /**
256      * Logs error messages. Similar to `console.error`.
257      *
258      * @param {Mixed[]} args
259      *        One or more messages or objects that should be logged as an error
260      */
263     log.error = function () {
264       for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
265         args[_key2] = arguments[_key2];
266       }
268       return logByType('error', level, args);
269     };
270     /**
271      * Logs warning messages. Similar to `console.warn`.
272      *
273      * @param {Mixed[]} args
274      *        One or more messages or objects that should be logged as a warning.
275      */
278     log.warn = function () {
279       for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
280         args[_key3] = arguments[_key3];
281       }
283       return logByType('warn', level, args);
284     };
285     /**
286      * Logs debug messages. Similar to `console.debug`, but may also act as a comparable
287      * log if `console.debug` is not available
288      *
289      * @param {Mixed[]} args
290      *        One or more messages or objects that should be logged as debug.
291      */
294     log.debug = function () {
295       for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {
296         args[_key4] = arguments[_key4];
297       }
299       return logByType('debug', level, args);
300     };
302     return log;
303   }
305   /**
306    * @file log.js
307    * @module log
308    */
309   var log = createLogger('VIDEOJS');
310   var createLogger$1 = log.createLogger;
312   /**
313    * @file obj.js
314    * @module obj
315    */
317   /**
318    * @callback obj:EachCallback
319    *
320    * @param {Mixed} value
321    *        The current key for the object that is being iterated over.
322    *
323    * @param {string} key
324    *        The current key-value for object that is being iterated over
325    */
327   /**
328    * @callback obj:ReduceCallback
329    *
330    * @param {Mixed} accum
331    *        The value that is accumulating over the reduce loop.
332    *
333    * @param {Mixed} value
334    *        The current key for the object that is being iterated over.
335    *
336    * @param {string} key
337    *        The current key-value for object that is being iterated over
338    *
339    * @return {Mixed}
340    *         The new accumulated value.
341    */
342   var toString = Object.prototype.toString;
343   /**
344    * Get the keys of an Object
345    *
346    * @param {Object}
347    *        The Object to get the keys from
348    *
349    * @return {string[]}
350    *         An array of the keys from the object. Returns an empty array if the
351    *         object passed in was invalid or had no keys.
352    *
353    * @private
354    */
356   var keys = function keys(object) {
357     return isObject(object) ? Object.keys(object) : [];
358   };
359   /**
360    * Array-like iteration for objects.
361    *
362    * @param {Object} object
363    *        The object to iterate over
364    *
365    * @param {obj:EachCallback} fn
366    *        The callback function which is called for each key in the object.
367    */
370   function each(object, fn) {
371     keys(object).forEach(function (key) {
372       return fn(object[key], key);
373     });
374   }
375   /**
376    * Array-like reduce for objects.
377    *
378    * @param {Object} object
379    *        The Object that you want to reduce.
380    *
381    * @param {Function} fn
382    *         A callback function which is called for each key in the object. It
383    *         receives the accumulated value and the per-iteration value and key
384    *         as arguments.
385    *
386    * @param {Mixed} [initial = 0]
387    *        Starting value
388    *
389    * @return {Mixed}
390    *         The final accumulated value.
391    */
393   function reduce(object, fn, initial) {
394     if (initial === void 0) {
395       initial = 0;
396     }
398     return keys(object).reduce(function (accum, key) {
399       return fn(accum, object[key], key);
400     }, initial);
401   }
402   /**
403    * Object.assign-style object shallow merge/extend.
404    *
405    * @param  {Object} target
406    * @param  {Object} ...sources
407    * @return {Object}
408    */
410   function assign(target) {
411     for (var _len = arguments.length, sources = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
412       sources[_key - 1] = arguments[_key];
413     }
415     if (Object.assign) {
416       return Object.assign.apply(Object, [target].concat(sources));
417     }
419     sources.forEach(function (source) {
420       if (!source) {
421         return;
422       }
424       each(source, function (value, key) {
425         target[key] = value;
426       });
427     });
428     return target;
429   }
430   /**
431    * Returns whether a value is an object of any kind - including DOM nodes,
432    * arrays, regular expressions, etc. Not functions, though.
433    *
434    * This avoids the gotcha where using `typeof` on a `null` value
435    * results in `'object'`.
436    *
437    * @param  {Object} value
438    * @return {boolean}
439    */
441   function isObject(value) {
442     return !!value && typeof value === 'object';
443   }
444   /**
445    * Returns whether an object appears to be a "plain" object - that is, a
446    * direct instance of `Object`.
447    *
448    * @param  {Object} value
449    * @return {boolean}
450    */
452   function isPlain(value) {
453     return isObject(value) && toString.call(value) === '[object Object]' && value.constructor === Object;
454   }
456   /**
457    * @file computed-style.js
458    * @module computed-style
459    */
460   /**
461    * A safe getComputedStyle.
462    *
463    * This is needed because in Firefox, if the player is loaded in an iframe with
464    * `display:none`, then `getComputedStyle` returns `null`, so, we do a
465    * null-check to make sure that the player doesn't break in these cases.
466    *
467    * @function
468    * @param    {Element} el
469    *           The element you want the computed style of
470    *
471    * @param    {string} prop
472    *           The property name you want
473    *
474    * @see      https://bugzilla.mozilla.org/show_bug.cgi?id=548397
475    */
477   function computedStyle(el, prop) {
478     if (!el || !prop) {
479       return '';
480     }
482     if (typeof window$1.getComputedStyle === 'function') {
483       var computedStyleValue = window$1.getComputedStyle(el);
484       return computedStyleValue ? computedStyleValue.getPropertyValue(prop) || computedStyleValue[prop] : '';
485     }
487     return '';
488   }
490   /**
491    * @file dom.js
492    * @module dom
493    */
494   /**
495    * Detect if a value is a string with any non-whitespace characters.
496    *
497    * @private
498    * @param  {string} str
499    *         The string to check
500    *
501    * @return {boolean}
502    *         Will be `true` if the string is non-blank, `false` otherwise.
503    *
504    */
506   function isNonBlankString(str) {
507     return typeof str === 'string' && /\S/.test(str);
508   }
509   /**
510    * Throws an error if the passed string has whitespace. This is used by
511    * class methods to be relatively consistent with the classList API.
512    *
513    * @private
514    * @param  {string} str
515    *         The string to check for whitespace.
516    *
517    * @throws {Error}
518    *         Throws an error if there is whitespace in the string.
519    */
522   function throwIfWhitespace(str) {
523     if (/\s/.test(str)) {
524       throw new Error('class has illegal whitespace characters');
525     }
526   }
527   /**
528    * Produce a regular expression for matching a className within an elements className.
529    *
530    * @private
531    * @param  {string} className
532    *         The className to generate the RegExp for.
533    *
534    * @return {RegExp}
535    *         The RegExp that will check for a specific `className` in an elements
536    *         className.
537    */
540   function classRegExp(className) {
541     return new RegExp('(^|\\s)' + className + '($|\\s)');
542   }
543   /**
544    * Whether the current DOM interface appears to be real (i.e. not simulated).
545    *
546    * @return {boolean}
547    *         Will be `true` if the DOM appears to be real, `false` otherwise.
548    */
551   function isReal() {
552     // Both document and window will never be undefined thanks to `global`.
553     return document === window$1.document;
554   }
555   /**
556    * Determines, via duck typing, whether or not a value is a DOM element.
557    *
558    * @param  {Mixed} value
559    *         The value to check.
560    *
561    * @return {boolean}
562    *         Will be `true` if the value is a DOM element, `false` otherwise.
563    */
565   function isEl(value) {
566     return isObject(value) && value.nodeType === 1;
567   }
568   /**
569    * Determines if the current DOM is embedded in an iframe.
570    *
571    * @return {boolean}
572    *         Will be `true` if the DOM is embedded in an iframe, `false`
573    *         otherwise.
574    */
576   function isInFrame() {
577     // We need a try/catch here because Safari will throw errors when attempting
578     // to get either `parent` or `self`
579     try {
580       return window$1.parent !== window$1.self;
581     } catch (x) {
582       return true;
583     }
584   }
585   /**
586    * Creates functions to query the DOM using a given method.
587    *
588    * @private
589    * @param   {string} method
590    *          The method to create the query with.
591    *
592    * @return  {Function}
593    *          The query method
594    */
596   function createQuerier(method) {
597     return function (selector, context) {
598       if (!isNonBlankString(selector)) {
599         return document[method](null);
600       }
602       if (isNonBlankString(context)) {
603         context = document.querySelector(context);
604       }
606       var ctx = isEl(context) ? context : document;
607       return ctx[method] && ctx[method](selector);
608     };
609   }
610   /**
611    * Creates an element and applies properties, attributes, and inserts content.
612    *
613    * @param  {string} [tagName='div']
614    *         Name of tag to be created.
615    *
616    * @param  {Object} [properties={}]
617    *         Element properties to be applied.
618    *
619    * @param  {Object} [attributes={}]
620    *         Element attributes to be applied.
621    *
622    * @param {module:dom~ContentDescriptor} content
623    *        A content descriptor object.
624    *
625    * @return {Element}
626    *         The element that was created.
627    */
630   function createEl(tagName, properties, attributes, content) {
631     if (tagName === void 0) {
632       tagName = 'div';
633     }
635     if (properties === void 0) {
636       properties = {};
637     }
639     if (attributes === void 0) {
640       attributes = {};
641     }
643     var el = document.createElement(tagName);
644     Object.getOwnPropertyNames(properties).forEach(function (propName) {
645       var val = properties[propName]; // See #2176
646       // We originally were accepting both properties and attributes in the
647       // same object, but that doesn't work so well.
649       if (propName.indexOf('aria-') !== -1 || propName === 'role' || propName === 'type') {
650         log.warn('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 " + propName + " to " + val + "."));
651         el.setAttribute(propName, val); // Handle textContent since it's not supported everywhere and we have a
652         // method for it.
653       } else if (propName === 'textContent') {
654         textContent(el, val);
655       } else {
656         el[propName] = val;
657       }
658     });
659     Object.getOwnPropertyNames(attributes).forEach(function (attrName) {
660       el.setAttribute(attrName, attributes[attrName]);
661     });
663     if (content) {
664       appendContent(el, content);
665     }
667     return el;
668   }
669   /**
670    * Injects text into an element, replacing any existing contents entirely.
671    *
672    * @param  {Element} el
673    *         The element to add text content into
674    *
675    * @param  {string} text
676    *         The text content to add.
677    *
678    * @return {Element}
679    *         The element with added text content.
680    */
682   function textContent(el, text) {
683     if (typeof el.textContent === 'undefined') {
684       el.innerText = text;
685     } else {
686       el.textContent = text;
687     }
689     return el;
690   }
691   /**
692    * Insert an element as the first child node of another
693    *
694    * @param {Element} child
695    *        Element to insert
696    *
697    * @param {Element} parent
698    *        Element to insert child into
699    */
701   function prependTo(child, parent) {
702     if (parent.firstChild) {
703       parent.insertBefore(child, parent.firstChild);
704     } else {
705       parent.appendChild(child);
706     }
707   }
708   /**
709    * Check if an element has a class name.
710    *
711    * @param  {Element} element
712    *         Element to check
713    *
714    * @param  {string} classToCheck
715    *         Class name to check for
716    *
717    * @return {boolean}
718    *         Will be `true` if the element has a class, `false` otherwise.
719    *
720    * @throws {Error}
721    *         Throws an error if `classToCheck` has white space.
722    */
724   function hasClass(element, classToCheck) {
725     throwIfWhitespace(classToCheck);
727     if (element.classList) {
728       return element.classList.contains(classToCheck);
729     }
731     return classRegExp(classToCheck).test(element.className);
732   }
733   /**
734    * Add a class name to an element.
735    *
736    * @param  {Element} element
737    *         Element to add class name to.
738    *
739    * @param  {string} classToAdd
740    *         Class name to add.
741    *
742    * @return {Element}
743    *         The DOM element with the added class name.
744    */
746   function addClass(element, classToAdd) {
747     if (element.classList) {
748       element.classList.add(classToAdd); // Don't need to `throwIfWhitespace` here because `hasElClass` will do it
749       // in the case of classList not being supported.
750     } else if (!hasClass(element, classToAdd)) {
751       element.className = (element.className + ' ' + classToAdd).trim();
752     }
754     return element;
755   }
756   /**
757    * Remove a class name from an element.
758    *
759    * @param  {Element} element
760    *         Element to remove a class name from.
761    *
762    * @param  {string} classToRemove
763    *         Class name to remove
764    *
765    * @return {Element}
766    *         The DOM element with class name removed.
767    */
769   function removeClass(element, classToRemove) {
770     if (element.classList) {
771       element.classList.remove(classToRemove);
772     } else {
773       throwIfWhitespace(classToRemove);
774       element.className = element.className.split(/\s+/).filter(function (c) {
775         return c !== classToRemove;
776       }).join(' ');
777     }
779     return element;
780   }
781   /**
782    * The callback definition for toggleClass.
783    *
784    * @callback module:dom~PredicateCallback
785    * @param    {Element} element
786    *           The DOM element of the Component.
787    *
788    * @param    {string} classToToggle
789    *           The `className` that wants to be toggled
790    *
791    * @return   {boolean|undefined}
792    *           If `true` is returned, the `classToToggle` will be added to the
793    *           `element`. If `false`, the `classToToggle` will be removed from
794    *           the `element`. If `undefined`, the callback will be ignored.
795    */
797   /**
798    * Adds or removes a class name to/from an element depending on an optional
799    * condition or the presence/absence of the class name.
800    *
801    * @param  {Element} element
802    *         The element to toggle a class name on.
803    *
804    * @param  {string} classToToggle
805    *         The class that should be toggled.
806    *
807    * @param  {boolean|module:dom~PredicateCallback} [predicate]
808    *         See the return value for {@link module:dom~PredicateCallback}
809    *
810    * @return {Element}
811    *         The element with a class that has been toggled.
812    */
814   function toggleClass(element, classToToggle, predicate) {
815     // This CANNOT use `classList` internally because IE11 does not support the
816     // second parameter to the `classList.toggle()` method! Which is fine because
817     // `classList` will be used by the add/remove functions.
818     var has = hasClass(element, classToToggle);
820     if (typeof predicate === 'function') {
821       predicate = predicate(element, classToToggle);
822     }
824     if (typeof predicate !== 'boolean') {
825       predicate = !has;
826     } // If the necessary class operation matches the current state of the
827     // element, no action is required.
830     if (predicate === has) {
831       return;
832     }
834     if (predicate) {
835       addClass(element, classToToggle);
836     } else {
837       removeClass(element, classToToggle);
838     }
840     return element;
841   }
842   /**
843    * Apply attributes to an HTML element.
844    *
845    * @param {Element} el
846    *        Element to add attributes to.
847    *
848    * @param {Object} [attributes]
849    *        Attributes to be applied.
850    */
852   function setAttributes(el, attributes) {
853     Object.getOwnPropertyNames(attributes).forEach(function (attrName) {
854       var attrValue = attributes[attrName];
856       if (attrValue === null || typeof attrValue === 'undefined' || attrValue === false) {
857         el.removeAttribute(attrName);
858       } else {
859         el.setAttribute(attrName, attrValue === true ? '' : attrValue);
860       }
861     });
862   }
863   /**
864    * Get an element's attribute values, as defined on the HTML tag.
865    *
866    * Attributes are not the same as properties. They're defined on the tag
867    * or with setAttribute.
868    *
869    * @param  {Element} tag
870    *         Element from which to get tag attributes.
871    *
872    * @return {Object}
873    *         All attributes of the element. Boolean attributes will be `true` or
874    *         `false`, others will be strings.
875    */
877   function getAttributes(tag) {
878     var obj = {}; // known boolean attributes
879     // we can check for matching boolean properties, but not all browsers
880     // and not all tags know about these attributes, so, we still want to check them manually
882     var knownBooleans = ',' + 'autoplay,controls,playsinline,loop,muted,default,defaultMuted' + ',';
884     if (tag && tag.attributes && tag.attributes.length > 0) {
885       var attrs = tag.attributes;
887       for (var i = attrs.length - 1; i >= 0; i--) {
888         var attrName = attrs[i].name;
889         var attrVal = attrs[i].value; // check for known booleans
890         // the matching element property will return a value for typeof
892         if (typeof tag[attrName] === 'boolean' || knownBooleans.indexOf(',' + attrName + ',') !== -1) {
893           // the value of an included boolean attribute is typically an empty
894           // string ('') which would equal false if we just check for a false value.
895           // we also don't want support bad code like autoplay='false'
896           attrVal = attrVal !== null ? true : false;
897         }
899         obj[attrName] = attrVal;
900       }
901     }
903     return obj;
904   }
905   /**
906    * Get the value of an element's attribute.
907    *
908    * @param {Element} el
909    *        A DOM element.
910    *
911    * @param {string} attribute
912    *        Attribute to get the value of.
913    *
914    * @return {string}
915    *         The value of the attribute.
916    */
918   function getAttribute(el, attribute) {
919     return el.getAttribute(attribute);
920   }
921   /**
922    * Set the value of an element's attribute.
923    *
924    * @param {Element} el
925    *        A DOM element.
926    *
927    * @param {string} attribute
928    *        Attribute to set.
929    *
930    * @param {string} value
931    *        Value to set the attribute to.
932    */
934   function setAttribute(el, attribute, value) {
935     el.setAttribute(attribute, value);
936   }
937   /**
938    * Remove an element's attribute.
939    *
940    * @param {Element} el
941    *        A DOM element.
942    *
943    * @param {string} attribute
944    *        Attribute to remove.
945    */
947   function removeAttribute(el, attribute) {
948     el.removeAttribute(attribute);
949   }
950   /**
951    * Attempt to block the ability to select text.
952    */
954   function blockTextSelection() {
955     document.body.focus();
957     document.onselectstart = function () {
958       return false;
959     };
960   }
961   /**
962    * Turn off text selection blocking.
963    */
965   function unblockTextSelection() {
966     document.onselectstart = function () {
967       return true;
968     };
969   }
970   /**
971    * Identical to the native `getBoundingClientRect` function, but ensures that
972    * the method is supported at all (it is in all browsers we claim to support)
973    * and that the element is in the DOM before continuing.
974    *
975    * This wrapper function also shims properties which are not provided by some
976    * older browsers (namely, IE8).
977    *
978    * Additionally, some browsers do not support adding properties to a
979    * `ClientRect`/`DOMRect` object; so, we shallow-copy it with the standard
980    * properties (except `x` and `y` which are not widely supported). This helps
981    * avoid implementations where keys are non-enumerable.
982    *
983    * @param  {Element} el
984    *         Element whose `ClientRect` we want to calculate.
985    *
986    * @return {Object|undefined}
987    *         Always returns a plain object - or `undefined` if it cannot.
988    */
990   function getBoundingClientRect(el) {
991     if (el && el.getBoundingClientRect && el.parentNode) {
992       var rect = el.getBoundingClientRect();
993       var result = {};
994       ['bottom', 'height', 'left', 'right', 'top', 'width'].forEach(function (k) {
995         if (rect[k] !== undefined) {
996           result[k] = rect[k];
997         }
998       });
1000       if (!result.height) {
1001         result.height = parseFloat(computedStyle(el, 'height'));
1002       }
1004       if (!result.width) {
1005         result.width = parseFloat(computedStyle(el, 'width'));
1006       }
1008       return result;
1009     }
1010   }
1011   /**
1012    * Represents the position of a DOM element on the page.
1013    *
1014    * @typedef  {Object} module:dom~Position
1015    *
1016    * @property {number} left
1017    *           Pixels to the left.
1018    *
1019    * @property {number} top
1020    *           Pixels from the top.
1021    */
1023   /**
1024    * Get the position of an element in the DOM.
1025    *
1026    * Uses `getBoundingClientRect` technique from John Resig.
1027    *
1028    * @see http://ejohn.org/blog/getboundingclientrect-is-awesome/
1029    *
1030    * @param  {Element} el
1031    *         Element from which to get offset.
1032    *
1033    * @return {module:dom~Position}
1034    *         The position of the element that was passed in.
1035    */
1037   function findPosition(el) {
1038     var box;
1040     if (el.getBoundingClientRect && el.parentNode) {
1041       box = el.getBoundingClientRect();
1042     }
1044     if (!box) {
1045       return {
1046         left: 0,
1047         top: 0
1048       };
1049     }
1051     var docEl = document.documentElement;
1052     var body = document.body;
1053     var clientLeft = docEl.clientLeft || body.clientLeft || 0;
1054     var scrollLeft = window$1.pageXOffset || body.scrollLeft;
1055     var left = box.left + scrollLeft - clientLeft;
1056     var clientTop = docEl.clientTop || body.clientTop || 0;
1057     var scrollTop = window$1.pageYOffset || body.scrollTop;
1058     var top = box.top + scrollTop - clientTop; // Android sometimes returns slightly off decimal values, so need to round
1060     return {
1061       left: Math.round(left),
1062       top: Math.round(top)
1063     };
1064   }
1065   /**
1066    * Represents x and y coordinates for a DOM element or mouse pointer.
1067    *
1068    * @typedef  {Object} module:dom~Coordinates
1069    *
1070    * @property {number} x
1071    *           x coordinate in pixels
1072    *
1073    * @property {number} y
1074    *           y coordinate in pixels
1075    */
1077   /**
1078    * Get the pointer position within an element.
1079    *
1080    * The base on the coordinates are the bottom left of the element.
1081    *
1082    * @param  {Element} el
1083    *         Element on which to get the pointer position on.
1084    *
1085    * @param  {EventTarget~Event} event
1086    *         Event object.
1087    *
1088    * @return {module:dom~Coordinates}
1089    *         A coordinates object corresponding to the mouse position.
1090    *
1091    */
1093   function getPointerPosition(el, event) {
1094     var position = {};
1095     var box = findPosition(el);
1096     var boxW = el.offsetWidth;
1097     var boxH = el.offsetHeight;
1098     var boxY = box.top;
1099     var boxX = box.left;
1100     var pageY = event.pageY;
1101     var pageX = event.pageX;
1103     if (event.changedTouches) {
1104       pageX = event.changedTouches[0].pageX;
1105       pageY = event.changedTouches[0].pageY;
1106     }
1108     position.y = Math.max(0, Math.min(1, (boxY - pageY + boxH) / boxH));
1109     position.x = Math.max(0, Math.min(1, (pageX - boxX) / boxW));
1110     return position;
1111   }
1112   /**
1113    * Determines, via duck typing, whether or not a value is a text node.
1114    *
1115    * @param  {Mixed} value
1116    *         Check if this value is a text node.
1117    *
1118    * @return {boolean}
1119    *         Will be `true` if the value is a text node, `false` otherwise.
1120    */
1122   function isTextNode(value) {
1123     return isObject(value) && value.nodeType === 3;
1124   }
1125   /**
1126    * Empties the contents of an element.
1127    *
1128    * @param  {Element} el
1129    *         The element to empty children from
1130    *
1131    * @return {Element}
1132    *         The element with no children
1133    */
1135   function emptyEl(el) {
1136     while (el.firstChild) {
1137       el.removeChild(el.firstChild);
1138     }
1140     return el;
1141   }
1142   /**
1143    * This is a mixed value that describes content to be injected into the DOM
1144    * via some method. It can be of the following types:
1145    *
1146    * Type       | Description
1147    * -----------|-------------
1148    * `string`   | The value will be normalized into a text node.
1149    * `Element`  | The value will be accepted as-is.
1150    * `TextNode` | The value will be accepted as-is.
1151    * `Array`    | A one-dimensional array of strings, elements, text nodes, or functions. These functions should return a string, element, or text node (any other return value, like an array, will be ignored).
1152    * `Function` | A function, which is expected to return a string, element, text node, or array - any of the other possible values described above. This means that a content descriptor could be a function that returns an array of functions, but those second-level functions must return strings, elements, or text nodes.
1153    *
1154    * @typedef {string|Element|TextNode|Array|Function} module:dom~ContentDescriptor
1155    */
1157   /**
1158    * Normalizes content for eventual insertion into the DOM.
1159    *
1160    * This allows a wide range of content definition methods, but helps protect
1161    * from falling into the trap of simply writing to `innerHTML`, which could
1162    * be an XSS concern.
1163    *
1164    * The content for an element can be passed in multiple types and
1165    * combinations, whose behavior is as follows:
1166    *
1167    * @param {module:dom~ContentDescriptor} content
1168    *        A content descriptor value.
1169    *
1170    * @return {Array}
1171    *         All of the content that was passed in, normalized to an array of
1172    *         elements or text nodes.
1173    */
1175   function normalizeContent(content) {
1176     // First, invoke content if it is a function. If it produces an array,
1177     // that needs to happen before normalization.
1178     if (typeof content === 'function') {
1179       content = content();
1180     } // Next up, normalize to an array, so one or many items can be normalized,
1181     // filtered, and returned.
1184     return (Array.isArray(content) ? content : [content]).map(function (value) {
1185       // First, invoke value if it is a function to produce a new value,
1186       // which will be subsequently normalized to a Node of some kind.
1187       if (typeof value === 'function') {
1188         value = value();
1189       }
1191       if (isEl(value) || isTextNode(value)) {
1192         return value;
1193       }
1195       if (typeof value === 'string' && /\S/.test(value)) {
1196         return document.createTextNode(value);
1197       }
1198     }).filter(function (value) {
1199       return value;
1200     });
1201   }
1202   /**
1203    * Normalizes and appends content to an element.
1204    *
1205    * @param  {Element} el
1206    *         Element to append normalized content to.
1207    *
1208    * @param {module:dom~ContentDescriptor} content
1209    *        A content descriptor value.
1210    *
1211    * @return {Element}
1212    *         The element with appended normalized content.
1213    */
1215   function appendContent(el, content) {
1216     normalizeContent(content).forEach(function (node) {
1217       return el.appendChild(node);
1218     });
1219     return el;
1220   }
1221   /**
1222    * Normalizes and inserts content into an element; this is identical to
1223    * `appendContent()`, except it empties the element first.
1224    *
1225    * @param {Element} el
1226    *        Element to insert normalized content into.
1227    *
1228    * @param {module:dom~ContentDescriptor} content
1229    *        A content descriptor value.
1230    *
1231    * @return {Element}
1232    *         The element with inserted normalized content.
1233    */
1235   function insertContent(el, content) {
1236     return appendContent(emptyEl(el), content);
1237   }
1238   /**
1239    * Check if an event was a single left click.
1240    *
1241    * @param  {EventTarget~Event} event
1242    *         Event object.
1243    *
1244    * @return {boolean}
1245    *         Will be `true` if a single left click, `false` otherwise.
1246    */
1248   function isSingleLeftClick(event) {
1249     // Note: if you create something draggable, be sure to
1250     // call it on both `mousedown` and `mousemove` event,
1251     // otherwise `mousedown` should be enough for a button
1252     if (event.button === undefined && event.buttons === undefined) {
1253       // Why do we need `buttons` ?
1254       // Because, middle mouse sometimes have this:
1255       // e.button === 0 and e.buttons === 4
1256       // Furthermore, we want to prevent combination click, something like
1257       // HOLD middlemouse then left click, that would be
1258       // e.button === 0, e.buttons === 5
1259       // just `button` is not gonna work
1260       // Alright, then what this block does ?
1261       // this is for chrome `simulate mobile devices`
1262       // I want to support this as well
1263       return true;
1264     }
1266     if (event.button === 0 && event.buttons === undefined) {
1267       // Touch screen, sometimes on some specific device, `buttons`
1268       // doesn't have anything (safari on ios, blackberry...)
1269       return true;
1270     } // `mouseup` event on a single left click has
1271     // `button` and `buttons` equal to 0
1274     if (event.type === 'mouseup' && event.button === 0 && event.buttons === 0) {
1275       return true;
1276     }
1278     if (event.button !== 0 || event.buttons !== 1) {
1279       // This is the reason we have those if else block above
1280       // if any special case we can catch and let it slide
1281       // we do it above, when get to here, this definitely
1282       // is-not-left-click
1283       return false;
1284     }
1286     return true;
1287   }
1288   /**
1289    * Finds a single DOM element matching `selector` within the optional
1290    * `context` of another DOM element (defaulting to `document`).
1291    *
1292    * @param  {string} selector
1293    *         A valid CSS selector, which will be passed to `querySelector`.
1294    *
1295    * @param  {Element|String} [context=document]
1296    *         A DOM element within which to query. Can also be a selector
1297    *         string in which case the first matching element will be used
1298    *         as context. If missing (or no element matches selector), falls
1299    *         back to `document`.
1300    *
1301    * @return {Element|null}
1302    *         The element that was found or null.
1303    */
1305   var $ = createQuerier('querySelector');
1306   /**
1307    * Finds a all DOM elements matching `selector` within the optional
1308    * `context` of another DOM element (defaulting to `document`).
1309    *
1310    * @param  {string} selector
1311    *         A valid CSS selector, which will be passed to `querySelectorAll`.
1312    *
1313    * @param  {Element|String} [context=document]
1314    *         A DOM element within which to query. Can also be a selector
1315    *         string in which case the first matching element will be used
1316    *         as context. If missing (or no element matches selector), falls
1317    *         back to `document`.
1318    *
1319    * @return {NodeList}
1320    *         A element list of elements that were found. Will be empty if none
1321    *         were found.
1322    *
1323    */
1325   var $$ = createQuerier('querySelectorAll');
1327   var Dom = /*#__PURE__*/Object.freeze({
1328     isReal: isReal,
1329     isEl: isEl,
1330     isInFrame: isInFrame,
1331     createEl: createEl,
1332     textContent: textContent,
1333     prependTo: prependTo,
1334     hasClass: hasClass,
1335     addClass: addClass,
1336     removeClass: removeClass,
1337     toggleClass: toggleClass,
1338     setAttributes: setAttributes,
1339     getAttributes: getAttributes,
1340     getAttribute: getAttribute,
1341     setAttribute: setAttribute,
1342     removeAttribute: removeAttribute,
1343     blockTextSelection: blockTextSelection,
1344     unblockTextSelection: unblockTextSelection,
1345     getBoundingClientRect: getBoundingClientRect,
1346     findPosition: findPosition,
1347     getPointerPosition: getPointerPosition,
1348     isTextNode: isTextNode,
1349     emptyEl: emptyEl,
1350     normalizeContent: normalizeContent,
1351     appendContent: appendContent,
1352     insertContent: insertContent,
1353     isSingleLeftClick: isSingleLeftClick,
1354     $: $,
1355     $$: $$
1356   });
1358   /**
1359    * @file setup.js - Functions for setting up a player without
1360    * user interaction based on the data-setup `attribute` of the video tag.
1361    *
1362    * @module setup
1363    */
1364   var _windowLoaded = false;
1365   var videojs;
1366   /**
1367    * Set up any tags that have a data-setup `attribute` when the player is started.
1368    */
1370   var autoSetup = function autoSetup() {
1371     // Protect against breakage in non-browser environments and check global autoSetup option.
1372     if (!isReal() || videojs.options.autoSetup === false) {
1373       return;
1374     }
1376     var vids = Array.prototype.slice.call(document.getElementsByTagName('video'));
1377     var audios = Array.prototype.slice.call(document.getElementsByTagName('audio'));
1378     var divs = Array.prototype.slice.call(document.getElementsByTagName('video-js'));
1379     var mediaEls = vids.concat(audios, divs); // Check if any media elements exist
1381     if (mediaEls && mediaEls.length > 0) {
1382       for (var i = 0, e = mediaEls.length; i < e; i++) {
1383         var mediaEl = mediaEls[i]; // Check if element exists, has getAttribute func.
1385         if (mediaEl && mediaEl.getAttribute) {
1386           // Make sure this player hasn't already been set up.
1387           if (mediaEl.player === undefined) {
1388             var options = mediaEl.getAttribute('data-setup'); // Check if data-setup attr exists.
1389             // We only auto-setup if they've added the data-setup attr.
1391             if (options !== null) {
1392               // Create new video.js instance.
1393               videojs(mediaEl);
1394             }
1395           } // If getAttribute isn't defined, we need to wait for the DOM.
1397         } else {
1398           autoSetupTimeout(1);
1399           break;
1400         }
1401       } // No videos were found, so keep looping unless page is finished loading.
1403     } else if (!_windowLoaded) {
1404       autoSetupTimeout(1);
1405     }
1406   };
1407   /**
1408    * Wait until the page is loaded before running autoSetup. This will be called in
1409    * autoSetup if `hasLoaded` returns false.
1410    *
1411    * @param {number} wait
1412    *        How long to wait in ms
1413    *
1414    * @param {module:videojs} [vjs]
1415    *        The videojs library function
1416    */
1419   function autoSetupTimeout(wait, vjs) {
1420     if (vjs) {
1421       videojs = vjs;
1422     }
1424     window$1.setTimeout(autoSetup, wait);
1425   }
1426   /**
1427    * Used to set the internal tracking of window loaded state to true.
1428    *
1429    * @private
1430    */
1433   function setWindowLoaded() {
1434     _windowLoaded = true;
1435     window$1.removeEventListener('load', setWindowLoaded);
1436   }
1438   if (isReal()) {
1439     if (document.readyState === 'complete') {
1440       setWindowLoaded();
1441     } else {
1442       /**
1443        * Listen for the load event on window, and set _windowLoaded to true.
1444        *
1445        * We use a standard event listener here to avoid incrementing the GUID
1446        * before any players are created.
1447        *
1448        * @listens load
1449        */
1450       window$1.addEventListener('load', setWindowLoaded);
1451     }
1452   }
1454   /**
1455    * @file stylesheet.js
1456    * @module stylesheet
1457    */
1458   /**
1459    * Create a DOM syle element given a className for it.
1460    *
1461    * @param {string} className
1462    *        The className to add to the created style element.
1463    *
1464    * @return {Element}
1465    *         The element that was created.
1466    */
1468   var createStyleElement = function createStyleElement(className) {
1469     var style = document.createElement('style');
1470     style.className = className;
1471     return style;
1472   };
1473   /**
1474    * Add text to a DOM element.
1475    *
1476    * @param {Element} el
1477    *        The Element to add text content to.
1478    *
1479    * @param {string} content
1480    *        The text to add to the element.
1481    */
1483   var setTextContent = function setTextContent(el, content) {
1484     if (el.styleSheet) {
1485       el.styleSheet.cssText = content;
1486     } else {
1487       el.textContent = content;
1488     }
1489   };
1491   /**
1492    * @file dom-data.js
1493    * @module dom-data
1494    */
1496   /**
1497    * Element Data Store.
1498    *
1499    * Allows for binding data to an element without putting it directly on the
1500    * element. Ex. Event listeners are stored here.
1501    * (also from jsninja.com, slightly modified and updated for closure compiler)
1502    *
1503    * @type {Object}
1504    * @private
1505    */
1506   var DomData = new WeakMap();
1508   /**
1509    * @file guid.js
1510    * @module guid
1511    */
1512   // Default value for GUIDs. This allows us to reset the GUID counter in tests.
1513   //
1514   // The initial GUID is 3 because some users have come to rely on the first
1515   // default player ID ending up as `vjs_video_3`.
1516   //
1517   // See: https://github.com/videojs/video.js/pull/6216
1518   var _initialGuid = 3;
1519   /**
1520    * Unique ID for an element or function
1521    *
1522    * @type {Number}
1523    */
1525   var _guid = _initialGuid;
1526   /**
1527    * Get a unique auto-incrementing ID by number that has not been returned before.
1528    *
1529    * @return {number}
1530    *         A new unique ID.
1531    */
1533   function newGUID() {
1534     return _guid++;
1535   }
1537   /**
1538    * @file events.js. An Event System (John Resig - Secrets of a JS Ninja http://jsninja.com/)
1539    * (Original book version wasn't completely usable, so fixed some things and made Closure Compiler compatible)
1540    * This should work very similarly to jQuery's events, however it's based off the book version which isn't as
1541    * robust as jquery's, so there's probably some differences.
1542    *
1543    * @file events.js
1544    * @module events
1545    */
1546   /**
1547    * Clean up the listener cache and dispatchers
1548    *
1549    * @param {Element|Object} elem
1550    *        Element to clean up
1551    *
1552    * @param {string} type
1553    *        Type of event to clean up
1554    */
1556   function _cleanUpEvents(elem, type) {
1557     if (!DomData.has(elem)) {
1558       return;
1559     }
1561     var data = DomData.get(elem); // Remove the events of a particular type if there are none left
1563     if (data.handlers[type].length === 0) {
1564       delete data.handlers[type]; // data.handlers[type] = null;
1565       // Setting to null was causing an error with data.handlers
1566       // Remove the meta-handler from the element
1568       if (elem.removeEventListener) {
1569         elem.removeEventListener(type, data.dispatcher, false);
1570       } else if (elem.detachEvent) {
1571         elem.detachEvent('on' + type, data.dispatcher);
1572       }
1573     } // Remove the events object if there are no types left
1576     if (Object.getOwnPropertyNames(data.handlers).length <= 0) {
1577       delete data.handlers;
1578       delete data.dispatcher;
1579       delete data.disabled;
1580     } // Finally remove the element data if there is no data left
1583     if (Object.getOwnPropertyNames(data).length === 0) {
1584       DomData["delete"](elem);
1585     }
1586   }
1587   /**
1588    * Loops through an array of event types and calls the requested method for each type.
1589    *
1590    * @param {Function} fn
1591    *        The event method we want to use.
1592    *
1593    * @param {Element|Object} elem
1594    *        Element or object to bind listeners to
1595    *
1596    * @param {string} type
1597    *        Type of event to bind to.
1598    *
1599    * @param {EventTarget~EventListener} callback
1600    *        Event listener.
1601    */
1604   function _handleMultipleEvents(fn, elem, types, callback) {
1605     types.forEach(function (type) {
1606       // Call the event method for each one of the types
1607       fn(elem, type, callback);
1608     });
1609   }
1610   /**
1611    * Fix a native event to have standard property values
1612    *
1613    * @param {Object} event
1614    *        Event object to fix.
1615    *
1616    * @return {Object}
1617    *         Fixed event object.
1618    */
1621   function fixEvent(event) {
1622     function returnTrue() {
1623       return true;
1624     }
1626     function returnFalse() {
1627       return false;
1628     } // Test if fixing up is needed
1629     // Used to check if !event.stopPropagation instead of isPropagationStopped
1630     // But native events return true for stopPropagation, but don't have
1631     // other expected methods like isPropagationStopped. Seems to be a problem
1632     // with the Javascript Ninja code. So we're just overriding all events now.
1635     if (!event || !event.isPropagationStopped) {
1636       var old = event || window$1.event;
1637       event = {}; // Clone the old object so that we can modify the values event = {};
1638       // IE8 Doesn't like when you mess with native event properties
1639       // Firefox returns false for event.hasOwnProperty('type') and other props
1640       //  which makes copying more difficult.
1641       // TODO: Probably best to create a whitelist of event props
1643       for (var key in old) {
1644         // Safari 6.0.3 warns you if you try to copy deprecated layerX/Y
1645         // Chrome warns you if you try to copy deprecated keyboardEvent.keyLocation
1646         // and webkitMovementX/Y
1647         if (key !== 'layerX' && key !== 'layerY' && key !== 'keyLocation' && key !== 'webkitMovementX' && key !== 'webkitMovementY') {
1648           // Chrome 32+ warns if you try to copy deprecated returnValue, but
1649           // we still want to if preventDefault isn't supported (IE8).
1650           if (!(key === 'returnValue' && old.preventDefault)) {
1651             event[key] = old[key];
1652           }
1653         }
1654       } // The event occurred on this element
1657       if (!event.target) {
1658         event.target = event.srcElement || document;
1659       } // Handle which other element the event is related to
1662       if (!event.relatedTarget) {
1663         event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
1664       } // Stop the default browser action
1667       event.preventDefault = function () {
1668         if (old.preventDefault) {
1669           old.preventDefault();
1670         }
1672         event.returnValue = false;
1673         old.returnValue = false;
1674         event.defaultPrevented = true;
1675       };
1677       event.defaultPrevented = false; // Stop the event from bubbling
1679       event.stopPropagation = function () {
1680         if (old.stopPropagation) {
1681           old.stopPropagation();
1682         }
1684         event.cancelBubble = true;
1685         old.cancelBubble = true;
1686         event.isPropagationStopped = returnTrue;
1687       };
1689       event.isPropagationStopped = returnFalse; // Stop the event from bubbling and executing other handlers
1691       event.stopImmediatePropagation = function () {
1692         if (old.stopImmediatePropagation) {
1693           old.stopImmediatePropagation();
1694         }
1696         event.isImmediatePropagationStopped = returnTrue;
1697         event.stopPropagation();
1698       };
1700       event.isImmediatePropagationStopped = returnFalse; // Handle mouse position
1702       if (event.clientX !== null && event.clientX !== undefined) {
1703         var doc = document.documentElement;
1704         var body = document.body;
1705         event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
1706         event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
1707       } // Handle key presses
1710       event.which = event.charCode || event.keyCode; // Fix button for mouse clicks:
1711       // 0 == left; 1 == middle; 2 == right
1713       if (event.button !== null && event.button !== undefined) {
1714         // The following is disabled because it does not pass videojs-standard
1715         // and... yikes.
1717         /* eslint-disable */
1718         event.button = event.button & 1 ? 0 : event.button & 4 ? 1 : event.button & 2 ? 2 : 0;
1719         /* eslint-enable */
1720       }
1721     } // Returns fixed-up instance
1724     return event;
1725   }
1726   /**
1727    * Whether passive event listeners are supported
1728    */
1730   var _supportsPassive = false;
1732   (function () {
1733     try {
1734       var opts = Object.defineProperty({}, 'passive', {
1735         get: function get() {
1736           _supportsPassive = true;
1737         }
1738       });
1739       window$1.addEventListener('test', null, opts);
1740       window$1.removeEventListener('test', null, opts);
1741     } catch (e) {// disregard
1742     }
1743   })();
1744   /**
1745    * Touch events Chrome expects to be passive
1746    */
1749   var passiveEvents = ['touchstart', 'touchmove'];
1750   /**
1751    * Add an event listener to element
1752    * It stores the handler function in a separate cache object
1753    * and adds a generic handler to the element's event,
1754    * along with a unique id (guid) to the element.
1755    *
1756    * @param {Element|Object} elem
1757    *        Element or object to bind listeners to
1758    *
1759    * @param {string|string[]} type
1760    *        Type of event to bind to.
1761    *
1762    * @param {EventTarget~EventListener} fn
1763    *        Event listener.
1764    */
1766   function on(elem, type, fn) {
1767     if (Array.isArray(type)) {
1768       return _handleMultipleEvents(on, elem, type, fn);
1769     }
1771     if (!DomData.has(elem)) {
1772       DomData.set(elem, {});
1773     }
1775     var data = DomData.get(elem); // We need a place to store all our handler data
1777     if (!data.handlers) {
1778       data.handlers = {};
1779     }
1781     if (!data.handlers[type]) {
1782       data.handlers[type] = [];
1783     }
1785     if (!fn.guid) {
1786       fn.guid = newGUID();
1787     }
1789     data.handlers[type].push(fn);
1791     if (!data.dispatcher) {
1792       data.disabled = false;
1794       data.dispatcher = function (event, hash) {
1795         if (data.disabled) {
1796           return;
1797         }
1799         event = fixEvent(event);
1800         var handlers = data.handlers[event.type];
1802         if (handlers) {
1803           // Copy handlers so if handlers are added/removed during the process it doesn't throw everything off.
1804           var handlersCopy = handlers.slice(0);
1806           for (var m = 0, n = handlersCopy.length; m < n; m++) {
1807             if (event.isImmediatePropagationStopped()) {
1808               break;
1809             } else {
1810               try {
1811                 handlersCopy[m].call(elem, event, hash);
1812               } catch (e) {
1813                 log.error(e);
1814               }
1815             }
1816           }
1817         }
1818       };
1819     }
1821     if (data.handlers[type].length === 1) {
1822       if (elem.addEventListener) {
1823         var options = false;
1825         if (_supportsPassive && passiveEvents.indexOf(type) > -1) {
1826           options = {
1827             passive: true
1828           };
1829         }
1831         elem.addEventListener(type, data.dispatcher, options);
1832       } else if (elem.attachEvent) {
1833         elem.attachEvent('on' + type, data.dispatcher);
1834       }
1835     }
1836   }
1837   /**
1838    * Removes event listeners from an element
1839    *
1840    * @param {Element|Object} elem
1841    *        Object to remove listeners from.
1842    *
1843    * @param {string|string[]} [type]
1844    *        Type of listener to remove. Don't include to remove all events from element.
1845    *
1846    * @param {EventTarget~EventListener} [fn]
1847    *        Specific listener to remove. Don't include to remove listeners for an event
1848    *        type.
1849    */
1851   function off(elem, type, fn) {
1852     // Don't want to add a cache object through getElData if not needed
1853     if (!DomData.has(elem)) {
1854       return;
1855     }
1857     var data = DomData.get(elem); // If no events exist, nothing to unbind
1859     if (!data.handlers) {
1860       return;
1861     }
1863     if (Array.isArray(type)) {
1864       return _handleMultipleEvents(off, elem, type, fn);
1865     } // Utility function
1868     var removeType = function removeType(el, t) {
1869       data.handlers[t] = [];
1871       _cleanUpEvents(el, t);
1872     }; // Are we removing all bound events?
1875     if (type === undefined) {
1876       for (var t in data.handlers) {
1877         if (Object.prototype.hasOwnProperty.call(data.handlers || {}, t)) {
1878           removeType(elem, t);
1879         }
1880       }
1882       return;
1883     }
1885     var handlers = data.handlers[type]; // If no handlers exist, nothing to unbind
1887     if (!handlers) {
1888       return;
1889     } // If no listener was provided, remove all listeners for type
1892     if (!fn) {
1893       removeType(elem, type);
1894       return;
1895     } // We're only removing a single handler
1898     if (fn.guid) {
1899       for (var n = 0; n < handlers.length; n++) {
1900         if (handlers[n].guid === fn.guid) {
1901           handlers.splice(n--, 1);
1902         }
1903       }
1904     }
1906     _cleanUpEvents(elem, type);
1907   }
1908   /**
1909    * Trigger an event for an element
1910    *
1911    * @param {Element|Object} elem
1912    *        Element to trigger an event on
1913    *
1914    * @param {EventTarget~Event|string} event
1915    *        A string (the type) or an event object with a type attribute
1916    *
1917    * @param {Object} [hash]
1918    *        data hash to pass along with the event
1919    *
1920    * @return {boolean|undefined}
1921    *         Returns the opposite of `defaultPrevented` if default was
1922    *         prevented. Otherwise, returns `undefined`
1923    */
1925   function trigger(elem, event, hash) {
1926     // Fetches element data and a reference to the parent (for bubbling).
1927     // Don't want to add a data object to cache for every parent,
1928     // so checking hasElData first.
1929     var elemData = DomData.has(elem) ? DomData.get(elem) : {};
1930     var parent = elem.parentNode || elem.ownerDocument; // type = event.type || event,
1931     // handler;
1932     // If an event name was passed as a string, creates an event out of it
1934     if (typeof event === 'string') {
1935       event = {
1936         type: event,
1937         target: elem
1938       };
1939     } else if (!event.target) {
1940       event.target = elem;
1941     } // Normalizes the event properties.
1944     event = fixEvent(event); // If the passed element has a dispatcher, executes the established handlers.
1946     if (elemData.dispatcher) {
1947       elemData.dispatcher.call(elem, event, hash);
1948     } // Unless explicitly stopped or the event does not bubble (e.g. media events)
1949     // recursively calls this function to bubble the event up the DOM.
1952     if (parent && !event.isPropagationStopped() && event.bubbles === true) {
1953       trigger.call(null, parent, event, hash); // If at the top of the DOM, triggers the default action unless disabled.
1954     } else if (!parent && !event.defaultPrevented && event.target && event.target[event.type]) {
1955       if (!DomData.has(event.target)) {
1956         DomData.set(event.target, {});
1957       }
1959       var targetData = DomData.get(event.target); // Checks if the target has a default action for this event.
1961       if (event.target[event.type]) {
1962         // Temporarily disables event dispatching on the target as we have already executed the handler.
1963         targetData.disabled = true; // Executes the default action.
1965         if (typeof event.target[event.type] === 'function') {
1966           event.target[event.type]();
1967         } // Re-enables event dispatching.
1970         targetData.disabled = false;
1971       }
1972     } // Inform the triggerer if the default was prevented by returning false
1975     return !event.defaultPrevented;
1976   }
1977   /**
1978    * Trigger a listener only once for an event.
1979    *
1980    * @param {Element|Object} elem
1981    *        Element or object to bind to.
1982    *
1983    * @param {string|string[]} type
1984    *        Name/type of event
1985    *
1986    * @param {Event~EventListener} fn
1987    *        Event listener function
1988    */
1990   function one(elem, type, fn) {
1991     if (Array.isArray(type)) {
1992       return _handleMultipleEvents(one, elem, type, fn);
1993     }
1995     var func = function func() {
1996       off(elem, type, func);
1997       fn.apply(this, arguments);
1998     }; // copy the guid to the new function so it can removed using the original function's ID
2001     func.guid = fn.guid = fn.guid || newGUID();
2002     on(elem, type, func);
2003   }
2004   /**
2005    * Trigger a listener only once and then turn if off for all
2006    * configured events
2007    *
2008    * @param {Element|Object} elem
2009    *        Element or object to bind to.
2010    *
2011    * @param {string|string[]} type
2012    *        Name/type of event
2013    *
2014    * @param {Event~EventListener} fn
2015    *        Event listener function
2016    */
2018   function any(elem, type, fn) {
2019     var func = function func() {
2020       off(elem, type, func);
2021       fn.apply(this, arguments);
2022     }; // copy the guid to the new function so it can removed using the original function's ID
2025     func.guid = fn.guid = fn.guid || newGUID(); // multiple ons, but one off for everything
2027     on(elem, type, func);
2028   }
2030   var Events = /*#__PURE__*/Object.freeze({
2031     fixEvent: fixEvent,
2032     on: on,
2033     off: off,
2034     trigger: trigger,
2035     one: one,
2036     any: any
2037   });
2039   /**
2040    * @file fn.js
2041    * @module fn
2042    */
2043   var UPDATE_REFRESH_INTERVAL = 30;
2044   /**
2045    * Bind (a.k.a proxy or context). A simple method for changing the context of
2046    * a function.
2047    *
2048    * It also stores a unique id on the function so it can be easily removed from
2049    * events.
2050    *
2051    * @function
2052    * @param    {Mixed} context
2053    *           The object to bind as scope.
2054    *
2055    * @param    {Function} fn
2056    *           The function to be bound to a scope.
2057    *
2058    * @param    {number} [uid]
2059    *           An optional unique ID for the function to be set
2060    *
2061    * @return   {Function}
2062    *           The new function that will be bound into the context given
2063    */
2065   var bind = function bind(context, fn, uid) {
2066     // Make sure the function has a unique ID
2067     if (!fn.guid) {
2068       fn.guid = newGUID();
2069     } // Create the new function that changes the context
2072     var bound = fn.bind(context); // Allow for the ability to individualize this function
2073     // Needed in the case where multiple objects might share the same prototype
2074     // IF both items add an event listener with the same function, then you try to remove just one
2075     // it will remove both because they both have the same guid.
2076     // when using this, you need to use the bind method when you remove the listener as well.
2077     // currently used in text tracks
2079     bound.guid = uid ? uid + '_' + fn.guid : fn.guid;
2080     return bound;
2081   };
2082   /**
2083    * Wraps the given function, `fn`, with a new function that only invokes `fn`
2084    * at most once per every `wait` milliseconds.
2085    *
2086    * @function
2087    * @param    {Function} fn
2088    *           The function to be throttled.
2089    *
2090    * @param    {number}   wait
2091    *           The number of milliseconds by which to throttle.
2092    *
2093    * @return   {Function}
2094    */
2096   var throttle = function throttle(fn, wait) {
2097     var last = window$1.performance.now();
2099     var throttled = function throttled() {
2100       var now = window$1.performance.now();
2102       if (now - last >= wait) {
2103         fn.apply(void 0, arguments);
2104         last = now;
2105       }
2106     };
2108     return throttled;
2109   };
2110   /**
2111    * Creates a debounced function that delays invoking `func` until after `wait`
2112    * milliseconds have elapsed since the last time the debounced function was
2113    * invoked.
2114    *
2115    * Inspired by lodash and underscore implementations.
2116    *
2117    * @function
2118    * @param    {Function} func
2119    *           The function to wrap with debounce behavior.
2120    *
2121    * @param    {number} wait
2122    *           The number of milliseconds to wait after the last invocation.
2123    *
2124    * @param    {boolean} [immediate]
2125    *           Whether or not to invoke the function immediately upon creation.
2126    *
2127    * @param    {Object} [context=window]
2128    *           The "context" in which the debounced function should debounce. For
2129    *           example, if this function should be tied to a Video.js player,
2130    *           the player can be passed here. Alternatively, defaults to the
2131    *           global `window` object.
2132    *
2133    * @return   {Function}
2134    *           A debounced function.
2135    */
2137   var debounce = function debounce(func, wait, immediate, context) {
2138     if (context === void 0) {
2139       context = window$1;
2140     }
2142     var timeout;
2144     var cancel = function cancel() {
2145       context.clearTimeout(timeout);
2146       timeout = null;
2147     };
2148     /* eslint-disable consistent-this */
2151     var debounced = function debounced() {
2152       var self = this;
2153       var args = arguments;
2155       var _later = function later() {
2156         timeout = null;
2157         _later = null;
2159         if (!immediate) {
2160           func.apply(self, args);
2161         }
2162       };
2164       if (!timeout && immediate) {
2165         func.apply(self, args);
2166       }
2168       context.clearTimeout(timeout);
2169       timeout = context.setTimeout(_later, wait);
2170     };
2171     /* eslint-enable consistent-this */
2174     debounced.cancel = cancel;
2175     return debounced;
2176   };
2178   /**
2179    * @file src/js/event-target.js
2180    */
2181   /**
2182    * `EventTarget` is a class that can have the same API as the DOM `EventTarget`. It
2183    * adds shorthand functions that wrap around lengthy functions. For example:
2184    * the `on` function is a wrapper around `addEventListener`.
2185    *
2186    * @see [EventTarget Spec]{@link https://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventTarget}
2187    * @class EventTarget
2188    */
2190   var EventTarget = function EventTarget() {};
2191   /**
2192    * A Custom DOM event.
2193    *
2194    * @typedef {Object} EventTarget~Event
2195    * @see [Properties]{@link https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent}
2196    */
2198   /**
2199    * All event listeners should follow the following format.
2200    *
2201    * @callback EventTarget~EventListener
2202    * @this {EventTarget}
2203    *
2204    * @param {EventTarget~Event} event
2205    *        the event that triggered this function
2206    *
2207    * @param {Object} [hash]
2208    *        hash of data sent during the event
2209    */
2211   /**
2212    * An object containing event names as keys and booleans as values.
2213    *
2214    * > NOTE: If an event name is set to a true value here {@link EventTarget#trigger}
2215    *         will have extra functionality. See that function for more information.
2216    *
2217    * @property EventTarget.prototype.allowedEvents_
2218    * @private
2219    */
2222   EventTarget.prototype.allowedEvents_ = {};
2223   /**
2224    * Adds an `event listener` to an instance of an `EventTarget`. An `event listener` is a
2225    * function that will get called when an event with a certain name gets triggered.
2226    *
2227    * @param {string|string[]} type
2228    *        An event name or an array of event names.
2229    *
2230    * @param {EventTarget~EventListener} fn
2231    *        The function to call with `EventTarget`s
2232    */
2234   EventTarget.prototype.on = function (type, fn) {
2235     // Remove the addEventListener alias before calling Events.on
2236     // so we don't get into an infinite type loop
2237     var ael = this.addEventListener;
2239     this.addEventListener = function () {};
2241     on(this, type, fn);
2242     this.addEventListener = ael;
2243   };
2244   /**
2245    * An alias of {@link EventTarget#on}. Allows `EventTarget` to mimic
2246    * the standard DOM API.
2247    *
2248    * @function
2249    * @see {@link EventTarget#on}
2250    */
2253   EventTarget.prototype.addEventListener = EventTarget.prototype.on;
2254   /**
2255    * Removes an `event listener` for a specific event from an instance of `EventTarget`.
2256    * This makes it so that the `event listener` will no longer get called when the
2257    * named event happens.
2258    *
2259    * @param {string|string[]} type
2260    *        An event name or an array of event names.
2261    *
2262    * @param {EventTarget~EventListener} fn
2263    *        The function to remove.
2264    */
2266   EventTarget.prototype.off = function (type, fn) {
2267     off(this, type, fn);
2268   };
2269   /**
2270    * An alias of {@link EventTarget#off}. Allows `EventTarget` to mimic
2271    * the standard DOM API.
2272    *
2273    * @function
2274    * @see {@link EventTarget#off}
2275    */
2278   EventTarget.prototype.removeEventListener = EventTarget.prototype.off;
2279   /**
2280    * This function will add an `event listener` that gets triggered only once. After the
2281    * first trigger it will get removed. This is like adding an `event listener`
2282    * with {@link EventTarget#on} that calls {@link EventTarget#off} on itself.
2283    *
2284    * @param {string|string[]} type
2285    *        An event name or an array of event names.
2286    *
2287    * @param {EventTarget~EventListener} fn
2288    *        The function to be called once for each event name.
2289    */
2291   EventTarget.prototype.one = function (type, fn) {
2292     // Remove the addEventListener aliasing Events.on
2293     // so we don't get into an infinite type loop
2294     var ael = this.addEventListener;
2296     this.addEventListener = function () {};
2298     one(this, type, fn);
2299     this.addEventListener = ael;
2300   };
2302   EventTarget.prototype.any = function (type, fn) {
2303     // Remove the addEventListener aliasing Events.on
2304     // so we don't get into an infinite type loop
2305     var ael = this.addEventListener;
2307     this.addEventListener = function () {};
2309     any(this, type, fn);
2310     this.addEventListener = ael;
2311   };
2312   /**
2313    * This function causes an event to happen. This will then cause any `event listeners`
2314    * that are waiting for that event, to get called. If there are no `event listeners`
2315    * for an event then nothing will happen.
2316    *
2317    * If the name of the `Event` that is being triggered is in `EventTarget.allowedEvents_`.
2318    * Trigger will also call the `on` + `uppercaseEventName` function.
2319    *
2320    * Example:
2321    * 'click' is in `EventTarget.allowedEvents_`, so, trigger will attempt to call
2322    * `onClick` if it exists.
2323    *
2324    * @param {string|EventTarget~Event|Object} event
2325    *        The name of the event, an `Event`, or an object with a key of type set to
2326    *        an event name.
2327    */
2330   EventTarget.prototype.trigger = function (event) {
2331     var type = event.type || event; // deprecation
2332     // In a future version we should default target to `this`
2333     // similar to how we default the target to `elem` in
2334     // `Events.trigger`. Right now the default `target` will be
2335     // `document` due to the `Event.fixEvent` call.
2337     if (typeof event === 'string') {
2338       event = {
2339         type: type
2340       };
2341     }
2343     event = fixEvent(event);
2345     if (this.allowedEvents_[type] && this['on' + type]) {
2346       this['on' + type](event);
2347     }
2349     trigger(this, event);
2350   };
2351   /**
2352    * An alias of {@link EventTarget#trigger}. Allows `EventTarget` to mimic
2353    * the standard DOM API.
2354    *
2355    * @function
2356    * @see {@link EventTarget#trigger}
2357    */
2360   EventTarget.prototype.dispatchEvent = EventTarget.prototype.trigger;
2361   var EVENT_MAP;
2363   EventTarget.prototype.queueTrigger = function (event) {
2364     var _this = this;
2366     // only set up EVENT_MAP if it'll be used
2367     if (!EVENT_MAP) {
2368       EVENT_MAP = new Map();
2369     }
2371     var type = event.type || event;
2372     var map = EVENT_MAP.get(this);
2374     if (!map) {
2375       map = new Map();
2376       EVENT_MAP.set(this, map);
2377     }
2379     var oldTimeout = map.get(type);
2380     map["delete"](type);
2381     window$1.clearTimeout(oldTimeout);
2382     var timeout = window$1.setTimeout(function () {
2383       // if we cleared out all timeouts for the current target, delete its map
2384       if (map.size === 0) {
2385         map = null;
2386         EVENT_MAP["delete"](_this);
2387       }
2389       _this.trigger(event);
2390     }, 0);
2391     map.set(type, timeout);
2392   };
2394   /**
2395    * @file mixins/evented.js
2396    * @module evented
2397    */
2398   /**
2399    * Returns whether or not an object has had the evented mixin applied.
2400    *
2401    * @param  {Object} object
2402    *         An object to test.
2403    *
2404    * @return {boolean}
2405    *         Whether or not the object appears to be evented.
2406    */
2408   var isEvented = function isEvented(object) {
2409     return object instanceof EventTarget || !!object.eventBusEl_ && ['on', 'one', 'off', 'trigger'].every(function (k) {
2410       return typeof object[k] === 'function';
2411     });
2412   };
2413   /**
2414    * Adds a callback to run after the evented mixin applied.
2415    *
2416    * @param  {Object} object
2417    *         An object to Add
2418    * @param  {Function} callback
2419    *         The callback to run.
2420    */
2423   var addEventedCallback = function addEventedCallback(target, callback) {
2424     if (isEvented(target)) {
2425       callback();
2426     } else {
2427       if (!target.eventedCallbacks) {
2428         target.eventedCallbacks = [];
2429       }
2431       target.eventedCallbacks.push(callback);
2432     }
2433   };
2434   /**
2435    * Whether a value is a valid event type - non-empty string or array.
2436    *
2437    * @private
2438    * @param  {string|Array} type
2439    *         The type value to test.
2440    *
2441    * @return {boolean}
2442    *         Whether or not the type is a valid event type.
2443    */
2446   var isValidEventType = function isValidEventType(type) {
2447     return (// The regex here verifies that the `type` contains at least one non-
2448       // whitespace character.
2449       typeof type === 'string' && /\S/.test(type) || Array.isArray(type) && !!type.length
2450     );
2451   };
2452   /**
2453    * Validates a value to determine if it is a valid event target. Throws if not.
2454    *
2455    * @private
2456    * @throws {Error}
2457    *         If the target does not appear to be a valid event target.
2458    *
2459    * @param  {Object} target
2460    *         The object to test.
2461    */
2464   var validateTarget = function validateTarget(target) {
2465     if (!target.nodeName && !isEvented(target)) {
2466       throw new Error('Invalid target; must be a DOM node or evented object.');
2467     }
2468   };
2469   /**
2470    * Validates a value to determine if it is a valid event target. Throws if not.
2471    *
2472    * @private
2473    * @throws {Error}
2474    *         If the type does not appear to be a valid event type.
2475    *
2476    * @param  {string|Array} type
2477    *         The type to test.
2478    */
2481   var validateEventType = function validateEventType(type) {
2482     if (!isValidEventType(type)) {
2483       throw new Error('Invalid event type; must be a non-empty string or array.');
2484     }
2485   };
2486   /**
2487    * Validates a value to determine if it is a valid listener. Throws if not.
2488    *
2489    * @private
2490    * @throws {Error}
2491    *         If the listener is not a function.
2492    *
2493    * @param  {Function} listener
2494    *         The listener to test.
2495    */
2498   var validateListener = function validateListener(listener) {
2499     if (typeof listener !== 'function') {
2500       throw new Error('Invalid listener; must be a function.');
2501     }
2502   };
2503   /**
2504    * Takes an array of arguments given to `on()` or `one()`, validates them, and
2505    * normalizes them into an object.
2506    *
2507    * @private
2508    * @param  {Object} self
2509    *         The evented object on which `on()` or `one()` was called. This
2510    *         object will be bound as the `this` value for the listener.
2511    *
2512    * @param  {Array} args
2513    *         An array of arguments passed to `on()` or `one()`.
2514    *
2515    * @return {Object}
2516    *         An object containing useful values for `on()` or `one()` calls.
2517    */
2520   var normalizeListenArgs = function normalizeListenArgs(self, args) {
2521     // If the number of arguments is less than 3, the target is always the
2522     // evented object itself.
2523     var isTargetingSelf = args.length < 3 || args[0] === self || args[0] === self.eventBusEl_;
2524     var target;
2525     var type;
2526     var listener;
2528     if (isTargetingSelf) {
2529       target = self.eventBusEl_; // Deal with cases where we got 3 arguments, but we are still listening to
2530       // the evented object itself.
2532       if (args.length >= 3) {
2533         args.shift();
2534       }
2536       type = args[0];
2537       listener = args[1];
2538     } else {
2539       target = args[0];
2540       type = args[1];
2541       listener = args[2];
2542     }
2544     validateTarget(target);
2545     validateEventType(type);
2546     validateListener(listener);
2547     listener = bind(self, listener);
2548     return {
2549       isTargetingSelf: isTargetingSelf,
2550       target: target,
2551       type: type,
2552       listener: listener
2553     };
2554   };
2555   /**
2556    * Adds the listener to the event type(s) on the target, normalizing for
2557    * the type of target.
2558    *
2559    * @private
2560    * @param  {Element|Object} target
2561    *         A DOM node or evented object.
2562    *
2563    * @param  {string} method
2564    *         The event binding method to use ("on" or "one").
2565    *
2566    * @param  {string|Array} type
2567    *         One or more event type(s).
2568    *
2569    * @param  {Function} listener
2570    *         A listener function.
2571    */
2574   var listen = function listen(target, method, type, listener) {
2575     validateTarget(target);
2577     if (target.nodeName) {
2578       Events[method](target, type, listener);
2579     } else {
2580       target[method](type, listener);
2581     }
2582   };
2583   /**
2584    * Contains methods that provide event capabilities to an object which is passed
2585    * to {@link module:evented|evented}.
2586    *
2587    * @mixin EventedMixin
2588    */
2591   var EventedMixin = {
2592     /**
2593      * Add a listener to an event (or events) on this object or another evented
2594      * object.
2595      *
2596      * @param  {string|Array|Element|Object} targetOrType
2597      *         If this is a string or array, it represents the event type(s)
2598      *         that will trigger the listener.
2599      *
2600      *         Another evented object can be passed here instead, which will
2601      *         cause the listener to listen for events on _that_ object.
2602      *
2603      *         In either case, the listener's `this` value will be bound to
2604      *         this object.
2605      *
2606      * @param  {string|Array|Function} typeOrListener
2607      *         If the first argument was a string or array, this should be the
2608      *         listener function. Otherwise, this is a string or array of event
2609      *         type(s).
2610      *
2611      * @param  {Function} [listener]
2612      *         If the first argument was another evented object, this will be
2613      *         the listener function.
2614      */
2615     on: function on() {
2616       var _this = this;
2618       for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
2619         args[_key] = arguments[_key];
2620       }
2622       var _normalizeListenArgs = normalizeListenArgs(this, args),
2623           isTargetingSelf = _normalizeListenArgs.isTargetingSelf,
2624           target = _normalizeListenArgs.target,
2625           type = _normalizeListenArgs.type,
2626           listener = _normalizeListenArgs.listener;
2628       listen(target, 'on', type, listener); // If this object is listening to another evented object.
2630       if (!isTargetingSelf) {
2631         // If this object is disposed, remove the listener.
2632         var removeListenerOnDispose = function removeListenerOnDispose() {
2633           return _this.off(target, type, listener);
2634         }; // Use the same function ID as the listener so we can remove it later it
2635         // using the ID of the original listener.
2638         removeListenerOnDispose.guid = listener.guid; // Add a listener to the target's dispose event as well. This ensures
2639         // that if the target is disposed BEFORE this object, we remove the
2640         // removal listener that was just added. Otherwise, we create a memory leak.
2642         var removeRemoverOnTargetDispose = function removeRemoverOnTargetDispose() {
2643           return _this.off('dispose', removeListenerOnDispose);
2644         }; // Use the same function ID as the listener so we can remove it later
2645         // it using the ID of the original listener.
2648         removeRemoverOnTargetDispose.guid = listener.guid;
2649         listen(this, 'on', 'dispose', removeListenerOnDispose);
2650         listen(target, 'on', 'dispose', removeRemoverOnTargetDispose);
2651       }
2652     },
2654     /**
2655      * Add a listener to an event (or events) on this object or another evented
2656      * object. The listener will be called once per event and then removed.
2657      *
2658      * @param  {string|Array|Element|Object} targetOrType
2659      *         If this is a string or array, it represents the event type(s)
2660      *         that will trigger the listener.
2661      *
2662      *         Another evented object can be passed here instead, which will
2663      *         cause the listener to listen for events on _that_ object.
2664      *
2665      *         In either case, the listener's `this` value will be bound to
2666      *         this object.
2667      *
2668      * @param  {string|Array|Function} typeOrListener
2669      *         If the first argument was a string or array, this should be the
2670      *         listener function. Otherwise, this is a string or array of event
2671      *         type(s).
2672      *
2673      * @param  {Function} [listener]
2674      *         If the first argument was another evented object, this will be
2675      *         the listener function.
2676      */
2677     one: function one() {
2678       var _this2 = this;
2680       for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
2681         args[_key2] = arguments[_key2];
2682       }
2684       var _normalizeListenArgs2 = normalizeListenArgs(this, args),
2685           isTargetingSelf = _normalizeListenArgs2.isTargetingSelf,
2686           target = _normalizeListenArgs2.target,
2687           type = _normalizeListenArgs2.type,
2688           listener = _normalizeListenArgs2.listener; // Targeting this evented object.
2691       if (isTargetingSelf) {
2692         listen(target, 'one', type, listener); // Targeting another evented object.
2693       } else {
2694         // TODO: This wrapper is incorrect! It should only
2695         //       remove the wrapper for the event type that called it.
2696         //       Instead all listners are removed on the first trigger!
2697         //       see https://github.com/videojs/video.js/issues/5962
2698         var wrapper = function wrapper() {
2699           _this2.off(target, type, wrapper);
2701           for (var _len3 = arguments.length, largs = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
2702             largs[_key3] = arguments[_key3];
2703           }
2705           listener.apply(null, largs);
2706         }; // Use the same function ID as the listener so we can remove it later
2707         // it using the ID of the original listener.
2710         wrapper.guid = listener.guid;
2711         listen(target, 'one', type, wrapper);
2712       }
2713     },
2715     /**
2716      * Add a listener to an event (or events) on this object or another evented
2717      * object. The listener will only be called once for the first event that is triggered
2718      * then removed.
2719      *
2720      * @param  {string|Array|Element|Object} targetOrType
2721      *         If this is a string or array, it represents the event type(s)
2722      *         that will trigger the listener.
2723      *
2724      *         Another evented object can be passed here instead, which will
2725      *         cause the listener to listen for events on _that_ object.
2726      *
2727      *         In either case, the listener's `this` value will be bound to
2728      *         this object.
2729      *
2730      * @param  {string|Array|Function} typeOrListener
2731      *         If the first argument was a string or array, this should be the
2732      *         listener function. Otherwise, this is a string or array of event
2733      *         type(s).
2734      *
2735      * @param  {Function} [listener]
2736      *         If the first argument was another evented object, this will be
2737      *         the listener function.
2738      */
2739     any: function any() {
2740       var _this3 = this;
2742       for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {
2743         args[_key4] = arguments[_key4];
2744       }
2746       var _normalizeListenArgs3 = normalizeListenArgs(this, args),
2747           isTargetingSelf = _normalizeListenArgs3.isTargetingSelf,
2748           target = _normalizeListenArgs3.target,
2749           type = _normalizeListenArgs3.type,
2750           listener = _normalizeListenArgs3.listener; // Targeting this evented object.
2753       if (isTargetingSelf) {
2754         listen(target, 'any', type, listener); // Targeting another evented object.
2755       } else {
2756         var wrapper = function wrapper() {
2757           _this3.off(target, type, wrapper);
2759           for (var _len5 = arguments.length, largs = new Array(_len5), _key5 = 0; _key5 < _len5; _key5++) {
2760             largs[_key5] = arguments[_key5];
2761           }
2763           listener.apply(null, largs);
2764         }; // Use the same function ID as the listener so we can remove it later
2765         // it using the ID of the original listener.
2768         wrapper.guid = listener.guid;
2769         listen(target, 'any', type, wrapper);
2770       }
2771     },
2773     /**
2774      * Removes listener(s) from event(s) on an evented object.
2775      *
2776      * @param  {string|Array|Element|Object} [targetOrType]
2777      *         If this is a string or array, it represents the event type(s).
2778      *
2779      *         Another evented object can be passed here instead, in which case
2780      *         ALL 3 arguments are _required_.
2781      *
2782      * @param  {string|Array|Function} [typeOrListener]
2783      *         If the first argument was a string or array, this may be the
2784      *         listener function. Otherwise, this is a string or array of event
2785      *         type(s).
2786      *
2787      * @param  {Function} [listener]
2788      *         If the first argument was another evented object, this will be
2789      *         the listener function; otherwise, _all_ listeners bound to the
2790      *         event type(s) will be removed.
2791      */
2792     off: function off$1(targetOrType, typeOrListener, listener) {
2793       // Targeting this evented object.
2794       if (!targetOrType || isValidEventType(targetOrType)) {
2795         off(this.eventBusEl_, targetOrType, typeOrListener); // Targeting another evented object.
2796       } else {
2797         var target = targetOrType;
2798         var type = typeOrListener; // Fail fast and in a meaningful way!
2800         validateTarget(target);
2801         validateEventType(type);
2802         validateListener(listener); // Ensure there's at least a guid, even if the function hasn't been used
2804         listener = bind(this, listener); // Remove the dispose listener on this evented object, which was given
2805         // the same guid as the event listener in on().
2807         this.off('dispose', listener);
2809         if (target.nodeName) {
2810           off(target, type, listener);
2811           off(target, 'dispose', listener);
2812         } else if (isEvented(target)) {
2813           target.off(type, listener);
2814           target.off('dispose', listener);
2815         }
2816       }
2817     },
2819     /**
2820      * Fire an event on this evented object, causing its listeners to be called.
2821      *
2822      * @param   {string|Object} event
2823      *          An event type or an object with a type property.
2824      *
2825      * @param   {Object} [hash]
2826      *          An additional object to pass along to listeners.
2827      *
2828      * @return {boolean}
2829      *          Whether or not the default behavior was prevented.
2830      */
2831     trigger: function trigger$1(event, hash) {
2832       return trigger(this.eventBusEl_, event, hash);
2833     }
2834   };
2835   /**
2836    * Applies {@link module:evented~EventedMixin|EventedMixin} to a target object.
2837    *
2838    * @param  {Object} target
2839    *         The object to which to add event methods.
2840    *
2841    * @param  {Object} [options={}]
2842    *         Options for customizing the mixin behavior.
2843    *
2844    * @param  {string} [options.eventBusKey]
2845    *         By default, adds a `eventBusEl_` DOM element to the target object,
2846    *         which is used as an event bus. If the target object already has a
2847    *         DOM element that should be used, pass its key here.
2848    *
2849    * @return {Object}
2850    *         The target object.
2851    */
2853   function evented(target, options) {
2854     if (options === void 0) {
2855       options = {};
2856     }
2858     var _options = options,
2859         eventBusKey = _options.eventBusKey; // Set or create the eventBusEl_.
2861     if (eventBusKey) {
2862       if (!target[eventBusKey].nodeName) {
2863         throw new Error("The eventBusKey \"" + eventBusKey + "\" does not refer to an element.");
2864       }
2866       target.eventBusEl_ = target[eventBusKey];
2867     } else {
2868       target.eventBusEl_ = createEl('span', {
2869         className: 'vjs-event-bus'
2870       });
2871     }
2873     assign(target, EventedMixin);
2875     if (target.eventedCallbacks) {
2876       target.eventedCallbacks.forEach(function (callback) {
2877         callback();
2878       });
2879     } // When any evented object is disposed, it removes all its listeners.
2882     target.on('dispose', function () {
2883       target.off();
2884       window$1.setTimeout(function () {
2885         target.eventBusEl_ = null;
2886       }, 0);
2887     });
2888     return target;
2889   }
2891   /**
2892    * @file mixins/stateful.js
2893    * @module stateful
2894    */
2895   /**
2896    * Contains methods that provide statefulness to an object which is passed
2897    * to {@link module:stateful}.
2898    *
2899    * @mixin StatefulMixin
2900    */
2902   var StatefulMixin = {
2903     /**
2904      * A hash containing arbitrary keys and values representing the state of
2905      * the object.
2906      *
2907      * @type {Object}
2908      */
2909     state: {},
2911     /**
2912      * Set the state of an object by mutating its
2913      * {@link module:stateful~StatefulMixin.state|state} object in place.
2914      *
2915      * @fires   module:stateful~StatefulMixin#statechanged
2916      * @param   {Object|Function} stateUpdates
2917      *          A new set of properties to shallow-merge into the plugin state.
2918      *          Can be a plain object or a function returning a plain object.
2919      *
2920      * @return {Object|undefined}
2921      *          An object containing changes that occurred. If no changes
2922      *          occurred, returns `undefined`.
2923      */
2924     setState: function setState(stateUpdates) {
2925       var _this = this;
2927       // Support providing the `stateUpdates` state as a function.
2928       if (typeof stateUpdates === 'function') {
2929         stateUpdates = stateUpdates();
2930       }
2932       var changes;
2933       each(stateUpdates, function (value, key) {
2934         // Record the change if the value is different from what's in the
2935         // current state.
2936         if (_this.state[key] !== value) {
2937           changes = changes || {};
2938           changes[key] = {
2939             from: _this.state[key],
2940             to: value
2941           };
2942         }
2944         _this.state[key] = value;
2945       }); // Only trigger "statechange" if there were changes AND we have a trigger
2946       // function. This allows us to not require that the target object be an
2947       // evented object.
2949       if (changes && isEvented(this)) {
2950         /**
2951          * An event triggered on an object that is both
2952          * {@link module:stateful|stateful} and {@link module:evented|evented}
2953          * indicating that its state has changed.
2954          *
2955          * @event    module:stateful~StatefulMixin#statechanged
2956          * @type     {Object}
2957          * @property {Object} changes
2958          *           A hash containing the properties that were changed and
2959          *           the values they were changed `from` and `to`.
2960          */
2961         this.trigger({
2962           changes: changes,
2963           type: 'statechanged'
2964         });
2965       }
2967       return changes;
2968     }
2969   };
2970   /**
2971    * Applies {@link module:stateful~StatefulMixin|StatefulMixin} to a target
2972    * object.
2973    *
2974    * If the target object is {@link module:evented|evented} and has a
2975    * `handleStateChanged` method, that method will be automatically bound to the
2976    * `statechanged` event on itself.
2977    *
2978    * @param   {Object} target
2979    *          The object to be made stateful.
2980    *
2981    * @param   {Object} [defaultState]
2982    *          A default set of properties to populate the newly-stateful object's
2983    *          `state` property.
2984    *
2985    * @return {Object}
2986    *          Returns the `target`.
2987    */
2989   function stateful(target, defaultState) {
2990     assign(target, StatefulMixin); // This happens after the mixing-in because we need to replace the `state`
2991     // added in that step.
2993     target.state = assign({}, target.state, defaultState); // Auto-bind the `handleStateChanged` method of the target object if it exists.
2995     if (typeof target.handleStateChanged === 'function' && isEvented(target)) {
2996       target.on('statechanged', target.handleStateChanged);
2997     }
2999     return target;
3000   }
3002   /**
3003    * @file string-cases.js
3004    * @module to-lower-case
3005    */
3007   /**
3008    * Lowercase the first letter of a string.
3009    *
3010    * @param {string} string
3011    *        String to be lowercased
3012    *
3013    * @return {string}
3014    *         The string with a lowercased first letter
3015    */
3016   var toLowerCase = function toLowerCase(string) {
3017     if (typeof string !== 'string') {
3018       return string;
3019     }
3021     return string.replace(/./, function (w) {
3022       return w.toLowerCase();
3023     });
3024   };
3025   /**
3026    * Uppercase the first letter of a string.
3027    *
3028    * @param {string} string
3029    *        String to be uppercased
3030    *
3031    * @return {string}
3032    *         The string with an uppercased first letter
3033    */
3035   var toTitleCase = function toTitleCase(string) {
3036     if (typeof string !== 'string') {
3037       return string;
3038     }
3040     return string.replace(/./, function (w) {
3041       return w.toUpperCase();
3042     });
3043   };
3044   /**
3045    * Compares the TitleCase versions of the two strings for equality.
3046    *
3047    * @param {string} str1
3048    *        The first string to compare
3049    *
3050    * @param {string} str2
3051    *        The second string to compare
3052    *
3053    * @return {boolean}
3054    *         Whether the TitleCase versions of the strings are equal
3055    */
3057   var titleCaseEquals = function titleCaseEquals(str1, str2) {
3058     return toTitleCase(str1) === toTitleCase(str2);
3059   };
3061   /**
3062    * @file merge-options.js
3063    * @module merge-options
3064    */
3065   /**
3066    * Merge two objects recursively.
3067    *
3068    * Performs a deep merge like
3069    * {@link https://lodash.com/docs/4.17.10#merge|lodash.merge}, but only merges
3070    * plain objects (not arrays, elements, or anything else).
3071    *
3072    * Non-plain object values will be copied directly from the right-most
3073    * argument.
3074    *
3075    * @static
3076    * @param   {Object[]} sources
3077    *          One or more objects to merge into a new object.
3078    *
3079    * @return {Object}
3080    *          A new object that is the merged result of all sources.
3081    */
3083   function mergeOptions() {
3084     var result = {};
3086     for (var _len = arguments.length, sources = new Array(_len), _key = 0; _key < _len; _key++) {
3087       sources[_key] = arguments[_key];
3088     }
3090     sources.forEach(function (source) {
3091       if (!source) {
3092         return;
3093       }
3095       each(source, function (value, key) {
3096         if (!isPlain(value)) {
3097           result[key] = value;
3098           return;
3099         }
3101         if (!isPlain(result[key])) {
3102           result[key] = {};
3103         }
3105         result[key] = mergeOptions(result[key], value);
3106       });
3107     });
3108     return result;
3109   }
3111   /**
3112    * Player Component - Base class for all UI objects
3113    *
3114    * @file component.js
3115    */
3116   /**
3117    * Base class for all UI Components.
3118    * Components are UI objects which represent both a javascript object and an element
3119    * in the DOM. They can be children of other components, and can have
3120    * children themselves.
3121    *
3122    * Components can also use methods from {@link EventTarget}
3123    */
3125   var Component =
3126   /*#__PURE__*/
3127   function () {
3128     /**
3129      * A callback that is called when a component is ready. Does not have any
3130      * paramters and any callback value will be ignored.
3131      *
3132      * @callback Component~ReadyCallback
3133      * @this Component
3134      */
3136     /**
3137      * Creates an instance of this class.
3138      *
3139      * @param {Player} player
3140      *        The `Player` that this class should be attached to.
3141      *
3142      * @param {Object} [options]
3143      *        The key/value store of player options.
3144      *
3145      * @param {Object[]} [options.children]
3146      *        An array of children objects to intialize this component with. Children objects have
3147      *        a name property that will be used if more than one component of the same type needs to be
3148      *        added.
3149      *
3150      * @param {Component~ReadyCallback} [ready]
3151      *        Function that gets called when the `Component` is ready.
3152      */
3153     function Component(player, options, ready) {
3154       // The component might be the player itself and we can't pass `this` to super
3155       if (!player && this.play) {
3156         this.player_ = player = this; // eslint-disable-line
3157       } else {
3158         this.player_ = player;
3159       } // Hold the reference to the parent component via `addChild` method
3162       this.parentComponent_ = null; // Make a copy of prototype.options_ to protect against overriding defaults
3164       this.options_ = mergeOptions({}, this.options_); // Updated options with supplied options
3166       options = this.options_ = mergeOptions(this.options_, options); // Get ID from options or options element if one is supplied
3168       this.id_ = options.id || options.el && options.el.id; // If there was no ID from the options, generate one
3170       if (!this.id_) {
3171         // Don't require the player ID function in the case of mock players
3172         var id = player && player.id && player.id() || 'no_player';
3173         this.id_ = id + "_component_" + newGUID();
3174       }
3176       this.name_ = options.name || null; // Create element if one wasn't provided in options
3178       if (options.el) {
3179         this.el_ = options.el;
3180       } else if (options.createEl !== false) {
3181         this.el_ = this.createEl();
3182       } // if evented is anything except false, we want to mixin in evented
3185       if (options.evented !== false) {
3186         // Make this an evented object and use `el_`, if available, as its event bus
3187         evented(this, {
3188           eventBusKey: this.el_ ? 'el_' : null
3189         });
3190       }
3192       stateful(this, this.constructor.defaultState);
3193       this.children_ = [];
3194       this.childIndex_ = {};
3195       this.childNameIndex_ = {};
3196       this.setTimeoutIds_ = new Set();
3197       this.setIntervalIds_ = new Set();
3198       this.rafIds_ = new Set();
3199       this.clearingTimersOnDispose_ = false; // Add any child components in options
3201       if (options.initChildren !== false) {
3202         this.initChildren();
3203       }
3205       this.ready(ready); // Don't want to trigger ready here or it will before init is actually
3206       // finished for all children that run this constructor
3208       if (options.reportTouchActivity !== false) {
3209         this.enableTouchActivity();
3210       }
3211     }
3212     /**
3213      * Dispose of the `Component` and all child components.
3214      *
3215      * @fires Component#dispose
3216      */
3219     var _proto = Component.prototype;
3221     _proto.dispose = function dispose() {
3222       /**
3223        * Triggered when a `Component` is disposed.
3224        *
3225        * @event Component#dispose
3226        * @type {EventTarget~Event}
3227        *
3228        * @property {boolean} [bubbles=false]
3229        *           set to false so that the close event does not
3230        *           bubble up
3231        */
3232       this.trigger({
3233         type: 'dispose',
3234         bubbles: false
3235       }); // Dispose all children.
3237       if (this.children_) {
3238         for (var i = this.children_.length - 1; i >= 0; i--) {
3239           if (this.children_[i].dispose) {
3240             this.children_[i].dispose();
3241           }
3242         }
3243       } // Delete child references
3246       this.children_ = null;
3247       this.childIndex_ = null;
3248       this.childNameIndex_ = null;
3249       this.parentComponent_ = null;
3251       if (this.el_) {
3252         // Remove element from DOM
3253         if (this.el_.parentNode) {
3254           this.el_.parentNode.removeChild(this.el_);
3255         }
3257         if (DomData.has(this.el_)) {
3258           DomData["delete"](this.el_);
3259         }
3261         this.el_ = null;
3262       } // remove reference to the player after disposing of the element
3265       this.player_ = null;
3266     }
3267     /**
3268      * Return the {@link Player} that the `Component` has attached to.
3269      *
3270      * @return {Player}
3271      *         The player that this `Component` has attached to.
3272      */
3273     ;
3275     _proto.player = function player() {
3276       return this.player_;
3277     }
3278     /**
3279      * Deep merge of options objects with new options.
3280      * > Note: When both `obj` and `options` contain properties whose values are objects.
3281      *         The two properties get merged using {@link module:mergeOptions}
3282      *
3283      * @param {Object} obj
3284      *        The object that contains new options.
3285      *
3286      * @return {Object}
3287      *         A new object of `this.options_` and `obj` merged together.
3288      */
3289     ;
3291     _proto.options = function options(obj) {
3292       if (!obj) {
3293         return this.options_;
3294       }
3296       this.options_ = mergeOptions(this.options_, obj);
3297       return this.options_;
3298     }
3299     /**
3300      * Get the `Component`s DOM element
3301      *
3302      * @return {Element}
3303      *         The DOM element for this `Component`.
3304      */
3305     ;
3307     _proto.el = function el() {
3308       return this.el_;
3309     }
3310     /**
3311      * Create the `Component`s DOM element.
3312      *
3313      * @param {string} [tagName]
3314      *        Element's DOM node type. e.g. 'div'
3315      *
3316      * @param {Object} [properties]
3317      *        An object of properties that should be set.
3318      *
3319      * @param {Object} [attributes]
3320      *        An object of attributes that should be set.
3321      *
3322      * @return {Element}
3323      *         The element that gets created.
3324      */
3325     ;
3327     _proto.createEl = function createEl$1(tagName, properties, attributes) {
3328       return createEl(tagName, properties, attributes);
3329     }
3330     /**
3331      * Localize a string given the string in english.
3332      *
3333      * If tokens are provided, it'll try and run a simple token replacement on the provided string.
3334      * The tokens it looks for look like `{1}` with the index being 1-indexed into the tokens array.
3335      *
3336      * If a `defaultValue` is provided, it'll use that over `string`,
3337      * if a value isn't found in provided language files.
3338      * This is useful if you want to have a descriptive key for token replacement
3339      * but have a succinct localized string and not require `en.json` to be included.
3340      *
3341      * Currently, it is used for the progress bar timing.
3342      * ```js
3343      * {
3344      *   "progress bar timing: currentTime={1} duration={2}": "{1} of {2}"
3345      * }
3346      * ```
3347      * It is then used like so:
3348      * ```js
3349      * this.localize('progress bar timing: currentTime={1} duration{2}',
3350      *               [this.player_.currentTime(), this.player_.duration()],
3351      *               '{1} of {2}');
3352      * ```
3353      *
3354      * Which outputs something like: `01:23 of 24:56`.
3355      *
3356      *
3357      * @param {string} string
3358      *        The string to localize and the key to lookup in the language files.
3359      * @param {string[]} [tokens]
3360      *        If the current item has token replacements, provide the tokens here.
3361      * @param {string} [defaultValue]
3362      *        Defaults to `string`. Can be a default value to use for token replacement
3363      *        if the lookup key is needed to be separate.
3364      *
3365      * @return {string}
3366      *         The localized string or if no localization exists the english string.
3367      */
3368     ;
3370     _proto.localize = function localize(string, tokens, defaultValue) {
3371       if (defaultValue === void 0) {
3372         defaultValue = string;
3373       }
3375       var code = this.player_.language && this.player_.language();
3376       var languages = this.player_.languages && this.player_.languages();
3377       var language = languages && languages[code];
3378       var primaryCode = code && code.split('-')[0];
3379       var primaryLang = languages && languages[primaryCode];
3380       var localizedString = defaultValue;
3382       if (language && language[string]) {
3383         localizedString = language[string];
3384       } else if (primaryLang && primaryLang[string]) {
3385         localizedString = primaryLang[string];
3386       }
3388       if (tokens) {
3389         localizedString = localizedString.replace(/\{(\d+)\}/g, function (match, index) {
3390           var value = tokens[index - 1];
3391           var ret = value;
3393           if (typeof value === 'undefined') {
3394             ret = match;
3395           }
3397           return ret;
3398         });
3399       }
3401       return localizedString;
3402     }
3403     /**
3404      * Return the `Component`s DOM element. This is where children get inserted.
3405      * This will usually be the the same as the element returned in {@link Component#el}.
3406      *
3407      * @return {Element}
3408      *         The content element for this `Component`.
3409      */
3410     ;
3412     _proto.contentEl = function contentEl() {
3413       return this.contentEl_ || this.el_;
3414     }
3415     /**
3416      * Get this `Component`s ID
3417      *
3418      * @return {string}
3419      *         The id of this `Component`
3420      */
3421     ;
3423     _proto.id = function id() {
3424       return this.id_;
3425     }
3426     /**
3427      * Get the `Component`s name. The name gets used to reference the `Component`
3428      * and is set during registration.
3429      *
3430      * @return {string}
3431      *         The name of this `Component`.
3432      */
3433     ;
3435     _proto.name = function name() {
3436       return this.name_;
3437     }
3438     /**
3439      * Get an array of all child components
3440      *
3441      * @return {Array}
3442      *         The children
3443      */
3444     ;
3446     _proto.children = function children() {
3447       return this.children_;
3448     }
3449     /**
3450      * Returns the child `Component` with the given `id`.
3451      *
3452      * @param {string} id
3453      *        The id of the child `Component` to get.
3454      *
3455      * @return {Component|undefined}
3456      *         The child `Component` with the given `id` or undefined.
3457      */
3458     ;
3460     _proto.getChildById = function getChildById(id) {
3461       return this.childIndex_[id];
3462     }
3463     /**
3464      * Returns the child `Component` with the given `name`.
3465      *
3466      * @param {string} name
3467      *        The name of the child `Component` to get.
3468      *
3469      * @return {Component|undefined}
3470      *         The child `Component` with the given `name` or undefined.
3471      */
3472     ;
3474     _proto.getChild = function getChild(name) {
3475       if (!name) {
3476         return;
3477       }
3479       return this.childNameIndex_[name];
3480     }
3481     /**
3482      * Add a child `Component` inside the current `Component`.
3483      *
3484      *
3485      * @param {string|Component} child
3486      *        The name or instance of a child to add.
3487      *
3488      * @param {Object} [options={}]
3489      *        The key/value store of options that will get passed to children of
3490      *        the child.
3491      *
3492      * @param {number} [index=this.children_.length]
3493      *        The index to attempt to add a child into.
3494      *
3495      * @return {Component}
3496      *         The `Component` that gets added as a child. When using a string the
3497      *         `Component` will get created by this process.
3498  &