/** * @license * video.js 5.19.2 * copyright brightcove, inc. * available under apache license version 2.0 * * * includes vtt.js * available under apache license version 2.0 * */ (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.videojs = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new error("cannot find module '"+o+"'");throw f.code="module_not_found",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 0 && arguments[0] !== undefined ? arguments[0] : 'button'; var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var attributes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; props = (0, _obj.assign)({ classname: this.buildcssclass() }, props); if (tag !== 'button') { _log2['default'].warn('creating a button with an html element of ' + tag + ' is deprecated; use clickablecomponent instead.'); // add properties for clickable element which is not a native html button props = (0, _obj.assign)({ tabindex: 0 }, props); // add aria attributes for clickable element which is not a native html button attributes = (0, _obj.assign)({ role: 'button' }, attributes); } // add attributes for button element attributes = (0, _obj.assign)({ // necessary since the default button type is "submit" 'type': 'button', // let the screen reader user know that the text of the button may change 'aria-live': 'polite' }, attributes); var el = _component2['default'].prototype.createel.call(this, tag, props, attributes); this.createcontroltextel(el); return el; }; /** * add a child `component` inside of this `button`. * * @param {string|component} child * the name or instance of a child to add. * * @param {object} [options={}] * the key/value store of options that will get passed to children of * the child. * * @return {component} * the `component` that gets added as a child. when using a string the * `component` will get created by this process. * * @deprecated since version 5 */ button.prototype.addchild = function addchild(child) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var classname = this.constructor.name; _log2['default'].warn('adding an actionable (user controllable) child to a button (' + classname + ') is not supported; use a clickablecomponent instead.'); // avoid the error message generated by clickablecomponent's addchild method return _component2['default'].prototype.addchild.call(this, child, options); }; /** * enable the `button` element so that it can be activated or clicked. use this with * {@link button#disable}. */ button.prototype.enable = function enable() { _clickablecomponent.prototype.enable.call(this); this.el_.removeattribute('disabled'); }; /** * enable the `button` element so that it cannot be activated or clicked. use this with * {@link button#enable}. */ button.prototype.disable = function disable() { _clickablecomponent.prototype.disable.call(this); this.el_.setattribute('disabled', 'disabled'); }; /** * this gets called when a `button` has focus and `keydown` is triggered via a key * press. * * @param {eventtarget~event} event * the event that caused this function to get called. * * @listens keydown */ button.prototype.handlekeypress = function handlekeypress(event) { // ignore space (32) or enter (13) key operation, which is handled by the browser for a button. if (event.which === 32 || event.which === 13) { return; } // pass keypress handling up for unsupported keys _clickablecomponent.prototype.handlekeypress.call(this, event); }; return button; }(_clickablecomponent2['default']); _component2['default'].registercomponent('button', button); exports['default'] = button; },{"3":3,"5":5,"86":86,"88":88}],3:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); var _dom = _dereq_(81); var dom = _interoprequirewildcard(_dom); var _events = _dereq_(82); var events = _interoprequirewildcard(_events); var _fn = _dereq_(83); var fn = _interoprequirewildcard(_fn); var _log = _dereq_(86); var _log2 = _interoprequiredefault(_log); var _document = _dereq_(94); var _document2 = _interoprequiredefault(_document); var _obj = _dereq_(88); function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file button.js */ /** * clickable component which is clickable or keyboard actionable, * but is not a native html button. * * @extends component */ var clickablecomponent = function (_component) { _inherits(clickablecomponent, _component); /** * creates an instance of this class. * * @param {player} player * the `player` that this class should be attached to. * * @param {object} [options] * the key/value store of player options. */ function clickablecomponent(player, options) { _classcallcheck(this, clickablecomponent); var _this = _possibleconstructorreturn(this, _component.call(this, player, options)); _this.emittapevents(); _this.enable(); return _this; } /** * create the `component`s dom element. * * @param {string} [tag=div] * the element's node type. * * @param {object} [props={}] * an object of properties that should be set on the element. * * @param {object} [attributes={}] * an object of attributes that should be set on the element. * * @return {element} * the element that gets created. */ clickablecomponent.prototype.createel = function createel() { var tag = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'div'; var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var attributes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; props = (0, _obj.assign)({ classname: this.buildcssclass(), tabindex: 0 }, props); if (tag === 'button') { _log2['default'].error('creating a clickablecomponent with an html element of ' + tag + ' is not supported; use a button instead.'); } // add aria attributes for clickable element which is not a native html button attributes = (0, _obj.assign)({ 'role': 'button', // let the screen reader user know that the text of the element may change 'aria-live': 'polite' }, attributes); this.tabindex_ = props.tabindex; var el = _component.prototype.createel.call(this, tag, props, attributes); this.createcontroltextel(el); return el; }; /** * create a control text element on this `component` * * @param {element} [el] * parent element for the control text. * * @return {element} * the control text element that gets created. */ clickablecomponent.prototype.createcontroltextel = function createcontroltextel(el) { this.controltextel_ = dom.createel('span', { classname: 'vjs-control-text' }); if (el) { el.appendchild(this.controltextel_); } this.controltext(this.controltext_, el); return this.controltextel_; }; /** * get or set the localize text to use for the controls on the `component`. * * @param {string} [text] * control text for element. * * @param {element} [el=this.el()] * element to set the title on. * * @return {string|clickablecomponent} * - the control text when getting * - returns itself when setting; method can be chained. */ clickablecomponent.prototype.controltext = function controltext(text) { var el = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.el(); if (!text) { return this.controltext_ || 'need text'; } var localizedtext = this.localize(text); this.controltext_ = text; this.controltextel_.innerhtml = localizedtext; if (!this.noniconcontrol) { // set title attribute if only an icon is shown el.setattribute('title', localizedtext); } return this; }; /** * builds the default dom `classname`. * * @return {string} * the dom `classname` for this object. */ clickablecomponent.prototype.buildcssclass = function buildcssclass() { return 'vjs-control vjs-button ' + _component.prototype.buildcssclass.call(this); }; /** * enable this `component`s element. * * @return {clickablecomponent} * returns itself; method can be chained. */ clickablecomponent.prototype.enable = function enable() { this.removeclass('vjs-disabled'); this.el_.setattribute('aria-disabled', 'false'); if (typeof this.tabindex_ !== 'undefined') { this.el_.setattribute('tabindex', this.tabindex_); } this.on('tap', this.handleclick); this.on('click', this.handleclick); this.on('focus', this.handlefocus); this.on('blur', this.handleblur); return this; }; /** * disable this `component`s element. * * @return {clickablecomponent} * returns itself; method can be chained. */ clickablecomponent.prototype.disable = function disable() { this.addclass('vjs-disabled'); this.el_.setattribute('aria-disabled', 'true'); if (typeof this.tabindex_ !== 'undefined') { this.el_.removeattribute('tabindex'); } this.off('tap', this.handleclick); this.off('click', this.handleclick); this.off('focus', this.handlefocus); this.off('blur', this.handleblur); return this; }; /** * this gets called when a `clickablecomponent` gets: * - clicked (via the `click` event, listening starts in the constructor) * - tapped (via the `tap` event, listening starts in the constructor) * - the following things happen in order: * 1. {@link clickablecomponent#handlefocus} is called via a `focus` event on the * `clickablecomponent`. * 2. {@link clickablecomponent#handlefocus} adds a listener for `keydown` on using * {@link clickablecomponent#handlekeypress}. * 3. `clickablecomponent` has not had a `blur` event (`blur` means that focus was lost). the user presses * the space or enter key. * 4. {@link clickablecomponent#handlekeypress} calls this function with the `keydown` * event as a parameter. * * @param {eventtarget~event} event * the `keydown`, `tap`, or `click` event that caused this function to be * called. * * @listens tap * @listens click * @abstract */ clickablecomponent.prototype.handleclick = function handleclick(event) {}; /** * this gets called when a `clickablecomponent` gains focus via a `focus` event. * turns on listening for `keydown` events. when they happen it * calls `this.handlekeypress`. * * @param {eventtarget~event} event * the `focus` event that caused this function to be called. * * @listens focus */ clickablecomponent.prototype.handlefocus = function handlefocus(event) { events.on(_document2['default'], 'keydown', fn.bind(this, this.handlekeypress)); }; /** * called when this clickablecomponent has focus and a key gets pressed down. by * default it will call `this.handleclick` when the key is space or enter. * * @param {eventtarget~event} event * the `keydown` event that caused this function to be called. * * @listens keydown */ clickablecomponent.prototype.handlekeypress = function handlekeypress(event) { // support space (32) or enter (13) key operation to fire a click event if (event.which === 32 || event.which === 13) { event.preventdefault(); this.handleclick(event); } else if (_component.prototype.handlekeypress) { // pass keypress handling up for unsupported keys _component.prototype.handlekeypress.call(this, event); } }; /** * called when a `clickablecomponent` loses focus. turns off the listener for * `keydown` events. which stops `this.handlekeypress` from getting called. * * @param {eventtarget~event} event * the `blur` event that caused this function to be called. * * @listens blur */ clickablecomponent.prototype.handleblur = function handleblur(event) { events.off(_document2['default'], 'keydown', fn.bind(this, this.handlekeypress)); }; return clickablecomponent; }(_component2['default']); _component2['default'].registercomponent('clickablecomponent', clickablecomponent); exports['default'] = clickablecomponent; },{"5":5,"81":81,"82":82,"83":83,"86":86,"88":88,"94":94}],4:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _button = _dereq_(2); var _button2 = _interoprequiredefault(_button); var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file close-button.js */ /** * the `closebutton` is a `{@link button}` that fires a `close` event when * it gets clicked. * * @extends button */ var closebutton = function (_button) { _inherits(closebutton, _button); /** * creates an instance of the this class. * * @param {player} player * the `player` that this class should be attached to. * * @param {object} [options] * the key/value store of player options. */ function closebutton(player, options) { _classcallcheck(this, closebutton); var _this = _possibleconstructorreturn(this, _button.call(this, player, options)); _this.controltext(options && options.controltext || _this.localize('close')); return _this; } /** * builds the default dom `classname`. * * @return {string} * the dom `classname` for this object. */ closebutton.prototype.buildcssclass = function buildcssclass() { return 'vjs-close-button ' + _button.prototype.buildcssclass.call(this); }; /** * this gets called when a `closebutton` gets clicked. see * {@link clickablecomponent#handleclick} for more information on when this will be * triggered * * @param {eventtarget~event} event * the `keydown`, `tap`, or `click` event that caused this function to be * called. * * @listens tap * @listens click * @fires closebutton#close */ closebutton.prototype.handleclick = function handleclick(event) { /** * triggered when the a `closebutton` is clicked. * * @event closebutton#close * @type {eventtarget~event} * * @property {boolean} [bubbles=false] * set to false so that the close event does not * bubble up to parents if there is no listener */ this.trigger({ type: 'close', bubbles: false }); }; return closebutton; }(_button2['default']); _component2['default'].registercomponent('closebutton', closebutton); exports['default'] = closebutton; },{"2":2,"5":5}],5:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _window = _dereq_(95); var _window2 = _interoprequiredefault(_window); var _dom = _dereq_(81); var dom = _interoprequirewildcard(_dom); var _fn = _dereq_(83); var fn = _interoprequirewildcard(_fn); var _guid = _dereq_(85); var guid = _interoprequirewildcard(_guid); var _events = _dereq_(82); var events = _interoprequirewildcard(_events); var _log = _dereq_(86); var _log2 = _interoprequiredefault(_log); var _totitlecase = _dereq_(91); var _totitlecase2 = _interoprequiredefault(_totitlecase); var _mergeoptions = _dereq_(87); var _mergeoptions2 = _interoprequiredefault(_mergeoptions); function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } /** * player component - base class for all ui objects * * @file component.js */ /** * base class for all ui components. * components are ui objects which represent both a javascript object and an element * in the dom. they can be children of other components, and can have * children themselves. * * components can also use methods from {@link eventtarget} */ var component = function () { /** * a callback that is called when a component is ready. does not have any * paramters and any callback value will be ignored. * * @callback component~readycallback * @this component */ /** * creates an instance of this class. * * @param {player} player * the `player` that this class should be attached to. * * @param {object} [options] * the key/value store of player options. # * @param {object[]} [options.children] * an array of children objects to intialize this component with. children objects have * a name property that will be used if more than one component of the same type needs to be * added. * * @param {component~readycallback} [ready] * function that gets called when the `component` is ready. */ function component(player, options, ready) { _classcallcheck(this, component); // the component might be the player itself and we can't pass `this` to super if (!player && this.play) { this.player_ = player = this; // eslint-disable-line } else { this.player_ = player; } // make a copy of prototype.options_ to protect against overriding defaults this.options_ = (0, _mergeoptions2['default'])({}, this.options_); // updated options with supplied options options = this.options_ = (0, _mergeoptions2['default'])(this.options_, options); // get id from options or options element if one is supplied this.id_ = options.id || options.el && options.el.id; // if there was no id from the options, generate one if (!this.id_) { // don't require the player id function in the case of mock players var id = player && player.id && player.id() || 'no_player'; this.id_ = id + '_component_' + guid.newguid(); } this.name_ = options.name || null; // create element if one wasn't provided in options if (options.el) { this.el_ = options.el; } else if (options.createel !== false) { this.el_ = this.createel(); } this.children_ = []; this.childindex_ = {}; this.childnameindex_ = {}; // add any child components in options if (options.initchildren !== false) { this.initchildren(); } this.ready(ready); // don't want to trigger ready here or it will before init is actually // finished for all children that run this constructor if (options.reporttouchactivity !== false) { this.enabletouchactivity(); } } /** * dispose of the `component` and all child components. * * @fires component#dispose */ component.prototype.dispose = function dispose() { /** * triggered when a `component` is disposed. * * @event component#dispose * @type {eventtarget~event} * * @property {boolean} [bubbles=false] * set to false so that the close event does not * bubble up */ this.trigger({ type: 'dispose', bubbles: false }); // dispose all children. if (this.children_) { for (var i = this.children_.length - 1; i >= 0; i--) { if (this.children_[i].dispose) { this.children_[i].dispose(); } } } // delete child references this.children_ = null; this.childindex_ = null; this.childnameindex_ = null; // remove all event listeners. this.off(); // remove element from dom if (this.el_.parentnode) { this.el_.parentnode.removechild(this.el_); } dom.removeeldata(this.el_); this.el_ = null; }; /** * return the {@link player} that the `component` has attached to. * * @return {player} * the player that this `component` has attached to. */ component.prototype.player = function player() { return this.player_; }; /** * deep merge of options objects with new options. * > note: when both `obj` and `options` contain properties whose values are objects. * the two properties get merged using {@link module:mergeoptions} * * @param {object} obj * the object that contains new options. * * @return {object} * a new object of `this.options_` and `obj` merged together. * * @deprecated since version 5 */ component.prototype.options = function options(obj) { _log2['default'].warn('this.options() has been deprecated and will be moved to the constructor in 6.0'); if (!obj) { return this.options_; } this.options_ = (0, _mergeoptions2['default'])(this.options_, obj); return this.options_; }; /** * get the `component`s dom element * * @return {element} * the dom element for this `component`. */ component.prototype.el = function el() { return this.el_; }; /** * create the `component`s dom element. * * @param {string} [tagname] * element's dom node type. e.g. 'div' * * @param {object} [properties] * an object of properties that should be set. * * @param {object} [attributes] * an object of attributes that should be set. * * @return {element} * the element that gets created. */ component.prototype.createel = function createel(tagname, properties, attributes) { return dom.createel(tagname, properties, attributes); }; /** * localize a string given the string in english. * * @param {string} string * the string to localize. * * @return {string} * the localized string or if no localization exists the english string. */ component.prototype.localize = function localize(string) { var code = this.player_.language && this.player_.language(); var languages = this.player_.languages && this.player_.languages(); if (!code || !languages) { return string; } var language = languages[code]; if (language && language[string]) { return language[string]; } var primarycode = code.split('-')[0]; var primarylang = languages[primarycode]; if (primarylang && primarylang[string]) { return primarylang[string]; } return string; }; /** * return the `component`s dom element. this is where children get inserted. * this will usually be the the same as the element returned in {@link component#el}. * * @return {element} * the content element for this `component`. */ component.prototype.contentel = function contentel() { return this.contentel_ || this.el_; }; /** * get this `component`s id * * @return {string} * the id of this `component` */ component.prototype.id = function id() { return this.id_; }; /** * get the `component`s name. the name gets used to reference the `component` * and is set during registration. * * @return {string} * the name of this `component`. */ component.prototype.name = function name() { return this.name_; }; /** * get an array of all child components * * @return {array} * the children */ component.prototype.children = function children() { return this.children_; }; /** * returns the child `component` with the given `id`. * * @param {string} id * the id of the child `component` to get. * * @return {component|undefined} * the child `component` with the given `id` or undefined. */ component.prototype.getchildbyid = function getchildbyid(id) { return this.childindex_[id]; }; /** * returns the child `component` with the given `name`. * * @param {string} name * the name of the child `component` to get. * * @return {component|undefined} * the child `component` with the given `name` or undefined. */ component.prototype.getchild = function getchild(name) { if (!name) { return; } name = (0, _totitlecase2['default'])(name); return this.childnameindex_[name]; }; /** * add a child `component` inside the current `component`. * * * @param {string|component} child * the name or instance of a child to add. * * @param {object} [options={}] * the key/value store of options that will get passed to children of * the child. * * @param {number} [index=this.children_.length] * the index to attempt to add a child into. * * @return {component} * the `component` that gets added as a child. when using a string the * `component` will get created by this process. */ component.prototype.addchild = function addchild(child) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var index = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.children_.length; var component = void 0; var componentname = void 0; // if child is a string, create component with options if (typeof child === 'string') { componentname = (0, _totitlecase2['default'])(child); // options can also be specified as a boolean, // so convert to an empty object if false. if (!options) { options = {}; } // same as above, but true is deprecated so show a warning. if (options === true) { _log2['default'].warn('initializing a child component with `true` is deprecated.' + 'children should be defined in an array when possible, ' + 'but if necessary use an object instead of `true`.'); options = {}; } var componentclassname = options.componentclass || componentname; // set name through options options.name = componentname; // create a new object & element for this controls set // if there's no .player_, this is a player var componentclass = component.getcomponent(componentclassname); if (!componentclass) { throw new error('component ' + componentclassname + ' does not exist'); } // data stored directly on the videojs object may be // misidentified as a component to retain // backwards-compatibility with 4.x. check to make sure the // component class can be instantiated. if (typeof componentclass !== 'function') { return null; } component = new componentclass(this.player_ || this, options); // child is a component instance } else { component = child; } this.children_.splice(index, 0, component); if (typeof component.id === 'function') { this.childindex_[component.id()] = component; } // if a name wasn't used to create the component, check if we can use the // name function of the component componentname = componentname || component.name && (0, _totitlecase2['default'])(component.name()); if (componentname) { this.childnameindex_[componentname] = component; } // add the ui object's element to the container div (box) // having an element is not required if (typeof component.el === 'function' && component.el()) { var childnodes = this.contentel().children; var refnode = childnodes[index] || null; this.contentel().insertbefore(component.el(), refnode); } // return so it can stored on parent object if desired. return component; }; /** * remove a child `component` from this `component`s list of children. also removes * the child `component`s element from this `component`s element. * * @param {component} component * the child `component` to remove. */ component.prototype.removechild = function removechild(component) { if (typeof component === 'string') { component = this.getchild(component); } if (!component || !this.children_) { return; } var childfound = false; for (var i = this.children_.length - 1; i >= 0; i--) { if (this.children_[i] === component) { childfound = true; this.children_.splice(i, 1); break; } } if (!childfound) { return; } this.childindex_[component.id()] = null; this.childnameindex_[component.name()] = null; var compel = component.el(); if (compel && compel.parentnode === this.contentel()) { this.contentel().removechild(component.el()); } }; /** * add and initialize default child `component`s based upon options. */ component.prototype.initchildren = function initchildren() { var _this = this; var children = this.options_.children; if (children) { // `this` is `parent` var parentoptions = this.options_; var handleadd = function handleadd(child) { var name = child.name; var opts = child.opts; // allow options for children to be set at the parent options // e.g. videojs(id, { controlbar: false }); // instead of videojs(id, { children: { controlbar: false }); if (parentoptions[name] !== undefined) { opts = parentoptions[name]; } // allow for disabling default components // e.g. options['children']['posterimage'] = false if (opts === false) { return; } // allow options to be passed as a simple boolean if no configuration // is necessary. if (opts === true) { opts = {}; } // we also want to pass the original player options // to each component as well so they don't need to // reach back into the player for options later. opts.playeroptions = _this.options_.playeroptions; // create and add the child component. // add a direct reference to the child by name on the parent instance. // if two of the same component are used, different names should be supplied // for each var newchild = _this.addchild(name, opts); if (newchild) { _this[name] = newchild; } }; // allow for an array of children details to passed in the options var workingchildren = void 0; var tech = component.getcomponent('tech'); if (array.isarray(children)) { workingchildren = children; } else { workingchildren = object.keys(children); } workingchildren // children that are in this.options_ but also in workingchildren would // give us extra children we do not want. so, we want to filter them out. .concat(object.keys(this.options_).filter(function (child) { return !workingchildren.some(function (wchild) { if (typeof wchild === 'string') { return child === wchild; } return child === wchild.name; }); })).map(function (child) { var name = void 0; var opts = void 0; if (typeof child === 'string') { name = child; opts = children[name] || _this.options_[name] || {}; } else { name = child.name; opts = child; } return { name: name, opts: opts }; }).filter(function (child) { // we have to make sure that child.name isn't in the techorder since // techs are registerd as components but can't aren't compatible // see https://github.com/videojs/video.js/issues/2772 var c = component.getcomponent(child.opts.componentclass || (0, _totitlecase2['default'])(child.name)); return c && !tech.istech(c); }).foreach(handleadd); } }; /** * builds the default dom class name. should be overriden by sub-components. * * @return {string} * the dom class name for this object. * * @abstract */ component.prototype.buildcssclass = function buildcssclass() { // child classes can include a function that does: // return 'class name' + this._super(); return ''; }; /** * add an `event listener` to this `component`s element. * * the benefit of using this over the following: * - `vjsevents.on(otherelement, 'eventname', myfunc)` * - `othercomponent.on('eventname', myfunc)` * * 1. is that the listeners will get cleaned up when either component gets disposed. * 1. it will also bind `mycomponent` as the context of `myfunc`. * > note: if you remove the element from the dom that has used `on` you need to * clean up references using: `mycomponent.trigger(el, 'dispose')` * this will also allow the browser to garbage collect it. in special * cases such as with `window` and `document`, which are both permanent, * this is not necessary. * * @param {string|component|string[]} [first] * the event name, and array of event names, or another `component`. * * @param {eventtarget~eventlistener|string|string[]} [second] * the listener function, an event name, or an array of events names. * * @param {eventtarget~eventlistener} [third] * the event handler if `first` is a `component` and `second` is an event name * or an array of event names. * * @return {component} * returns itself; method can be chained. * * @listens component#dispose */ component.prototype.on = function on(first, second, third) { var _this2 = this; if (typeof first === 'string' || array.isarray(first)) { events.on(this.el_, first, fn.bind(this, second)); // targeting another component or element } else { var target = first; var type = second; var fn = fn.bind(this, third); // when this component is disposed, remove the listener from the other component var removeondispose = function removeondispose() { return _this2.off(target, type, fn); }; // use the same function id so we can remove it later it using the id // of the original listener removeondispose.guid = fn.guid; this.on('dispose', removeondispose); // if the other component is disposed first we need to clean the reference // to the other component in this component's removeondispose listener // otherwise we create a memory leak. var cleanremover = function cleanremover() { return _this2.off('dispose', removeondispose); }; // add the same function id so we can easily remove it later cleanremover.guid = fn.guid; // check if this is a dom node if (first.nodename) { // add the listener to the other element events.on(target, type, fn); events.on(target, 'dispose', cleanremover); // should be a component // not using `instanceof component` because it makes mock players difficult } else if (typeof first.on === 'function') { // add the listener to the other component target.on(type, fn); target.on('dispose', cleanremover); } } return this; }; /** * remove an event listener from this `component`s element. if the second argument is * exluded all listeners for the type passed in as the first argument will be removed. * * @param {string|component|string[]} [first] * the event name, and array of event names, or another `component`. * * @param {eventtarget~eventlistener|string|string[]} [second] * the listener function, an event name, or an array of events names. * * @param {eventtarget~eventlistener} [third] * the event handler if `first` is a `component` and `second` is an event name * or an array of event names. * * @return {component} * returns itself; method can be chained. */ component.prototype.off = function off(first, second, third) { if (!first || typeof first === 'string' || array.isarray(first)) { events.off(this.el_, first, second); } else { var target = first; var type = second; // ensure there's at least a guid, even if the function hasn't been used var fn = fn.bind(this, third); // remove the dispose listener on this component, // which was given the same guid as the event listener this.off('dispose', fn); if (first.nodename) { // remove the listener events.off(target, type, fn); // remove the listener for cleaning the dispose listener events.off(target, 'dispose', fn); } else { target.off(type, fn); target.off('dispose', fn); } } return this; }; /** * add an event listener that gets triggered only once and then gets removed. * * @param {string|component|string[]} [first] * the event name, and array of event names, or another `component`. * * @param {eventtarget~eventlistener|string|string[]} [second] * the listener function, an event name, or an array of events names. * * @param {eventtarget~eventlistener} [third] * the event handler if `first` is a `component` and `second` is an event name * or an array of event names. * * @return {component} * returns itself; method can be chained. */ component.prototype.one = function one(first, second, third) { var _this3 = this, _arguments = arguments; if (typeof first === 'string' || array.isarray(first)) { events.one(this.el_, first, fn.bind(this, second)); } else { var target = first; var type = second; var fn = fn.bind(this, third); var newfunc = function newfunc() { _this3.off(target, type, newfunc); fn.apply(null, _arguments); }; // keep the same function id so we can remove it later newfunc.guid = fn.guid; this.on(target, type, newfunc); } return this; }; /** * trigger an event on an element. * * @param {eventtarget~event|object|string} event * the event name, and event, or an event-like object with a type attribute * set to the event name. * * @param {object} [hash] * data hash to pass along with the event * * @return {component} * returns itself; method can be chained. */ component.prototype.trigger = function trigger(event, hash) { events.trigger(this.el_, event, hash); return this; }; /** * bind a listener to the component's ready state. if the ready event has already * happened it will trigger the function immediately. * * @param {component~readycallback} fn * a function to call when ready is triggered. * * @param {boolean} [sync=false] * execute the listener synchronously if `component` is ready. * * @return {component} * returns itself; method can be chained. */ component.prototype.ready = function ready(fn) { var sync = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; if (fn) { if (this.isready_) { if (sync) { fn.call(this); } else { // call the function asynchronously by default for consistency this.settimeout(fn, 1); } } else { this.readyqueue_ = this.readyqueue_ || []; this.readyqueue_.push(fn); } } return this; }; /** * trigger all the ready listeners for this `component`. * * @fires component#ready */ component.prototype.triggerready = function triggerready() { this.isready_ = true; // ensure ready is triggerd asynchronously this.settimeout(function () { var readyqueue = this.readyqueue_; // reset ready queue this.readyqueue_ = []; if (readyqueue && readyqueue.length > 0) { readyqueue.foreach(function (fn) { fn.call(this); }, this); } // allow for using event listeners also /** * triggered when a `component` is ready. * * @event component#ready * @type {eventtarget~event} */ this.trigger('ready'); }, 1); }; /** * find a single dom element matching a `selector`. this can be within the `component`s * `contentel()` or another custom context. * * @param {string} selector * a valid css selector, which will be passed to `queryselector`. * * @param {element|string} [context=this.contentel()] * a dom element within which to query. can also be a selector string in * which case the first matching element will get used as context. if * missing `this.contentel()` gets used. if `this.contentel()` returns * nothing it falls back to `document`. * * @return {element|null} * the dom element that was found, or null * * @see [information on css selectors](https://developer.mozilla.org/en-us/docs/web/guide/css/getting_started/selectors) */ component.prototype.$ = function $(selector, context) { return dom.$(selector, context || this.contentel()); }; /** * finds all dom element matching a `selector`. this can be within the `component`s * `contentel()` or another custom context. * * @param {string} selector * a valid css selector, which will be passed to `queryselectorall`. * * @param {element|string} [context=this.contentel()] * a dom element within which to query. can also be a selector string in * which case the first matching element will get used as context. if * missing `this.contentel()` gets used. if `this.contentel()` returns * nothing it falls back to `document`. * * @return {nodelist} * a list of dom elements that were found * * @see [information on css selectors](https://developer.mozilla.org/en-us/docs/web/guide/css/getting_started/selectors) */ component.prototype.$$ = function $$(selector, context) { return dom.$$(selector, context || this.contentel()); }; /** * check if a component's element has a css class name. * * @param {string} classtocheck * css class name to check. * * @return {boolean} * - true if the `component` has the class. * - false if the `component` does not have the class` */ component.prototype.hasclass = function hasclass(classtocheck) { return dom.haselclass(this.el_, classtocheck); }; /** * add a css class name to the `component`s element. * * @param {string} classtoadd * css class name to add * * @return {component} * returns itself; method can be chained. */ component.prototype.addclass = function addclass(classtoadd) { dom.addelclass(this.el_, classtoadd); return this; }; /** * remove a css class name from the `component`s element. * * @param {string} classtoremove * css class name to remove * * @return {component} * returns itself; method can be chained. */ component.prototype.removeclass = function removeclass(classtoremove) { dom.removeelclass(this.el_, classtoremove); return this; }; /** * add or remove a css class name from the component's element. * - `classtotoggle` gets added when {@link component#hasclass} would return false. * - `classtotoggle` gets removed when {@link component#hasclass} would return true. * * @param {string} classtotoggle * the class to add or remove based on (@link component#hasclass} * * @param {boolean|dom~predicate} [predicate] * an {@link dom~predicate} function or a boolean * * @return {component} * returns itself; method can be chained. */ component.prototype.toggleclass = function toggleclass(classtotoggle, predicate) { dom.toggleelclass(this.el_, classtotoggle, predicate); return this; }; /** * show the `component`s element if it is hidden by removing the * 'vjs-hidden' class name from it. * * @return {component} * returns itself; method can be chained. */ component.prototype.show = function show() { this.removeclass('vjs-hidden'); return this; }; /** * hide the `component`s element if it is currently showing by adding the * 'vjs-hidden` class name to it. * * @return {component} * returns itself; method can be chained. */ component.prototype.hide = function hide() { this.addclass('vjs-hidden'); return this; }; /** * lock a `component`s element in its visible state by adding the 'vjs-lock-showing' * class name to it. used during fadein/fadeout. * * @return {component} * returns itself; method can be chained. * * @private */ component.prototype.lockshowing = function lockshowing() { this.addclass('vjs-lock-showing'); return this; }; /** * unlock a `component`s element from its visible state by removing the 'vjs-lock-showing' * class name from it. used during fadein/fadeout. * * @return {component} * returns itself; method can be chained. * * @private */ component.prototype.unlockshowing = function unlockshowing() { this.removeclass('vjs-lock-showing'); return this; }; /** * get the value of an attribute on the `component`s element. * * @param {string} attribute * name of the attribute to get the value from. * * @return {string|null} * - the value of the attribute that was asked for. * - can be an empty string on some browsers if the attribute does not exist * or has no value * - most browsers will return null if the attibute does not exist or has * no value. * * @see [dom api]{@link https://developer.mozilla.org/en-us/docs/web/api/element/getattribute} */ component.prototype.getattribute = function getattribute(attribute) { return dom.getattribute(this.el_, attribute); }; /** * set the value of an attribute on the `component`'s element * * @param {string} attribute * name of the attribute to set. * * @param {string} value * value to set the attribute to. * * @return {component} * returns itself; method can be chained. * * @see [dom api]{@link https://developer.mozilla.org/en-us/docs/web/api/element/setattribute} */ component.prototype.setattribute = function setattribute(attribute, value) { dom.setattribute(this.el_, attribute, value); return this; }; /** * remove an attribute from the `component`s element. * * @param {string} attribute * name of the attribute to remove. * * @return {component} * returns itself; method can be chained. * * @see [dom api]{@link https://developer.mozilla.org/en-us/docs/web/api/element/removeattribute} */ component.prototype.removeattribute = function removeattribute(attribute) { dom.removeattribute(this.el_, attribute); return this; }; /** * get or set the width of the component based upon the css styles. * see {@link component#dimension} for more detailed information. * * @param {number|string} [num] * the width that you want to set postfixed with '%', 'px' or nothing. * * @param {boolean} [skiplisteners] * skip the resize event trigger * * @return {component|number|string} * - the width when getting, zero if there is no width. can be a string * postpixed with '%' or 'px'. * - returns itself when setting; method can be chained. */ component.prototype.width = function width(num, skiplisteners) { return this.dimension('width', num, skiplisteners); }; /** * get or set the height of the component based upon the css styles. * see {@link component#dimension} for more detailed information. * * @param {number|string} [num] * the height that you want to set postfixed with '%', 'px' or nothing. * * @param {boolean} [skiplisteners] * skip the resize event trigger * * @return {component|number|string} * - the width when getting, zero if there is no width. can be a string * postpixed with '%' or 'px'. * - returns itself when setting; method can be chained. */ component.prototype.height = function height(num, skiplisteners) { return this.dimension('height', num, skiplisteners); }; /** * set both the width and height of the `component` element at the same time. * * @param {number|string} width * width to set the `component`s element to. * * @param {number|string} height * height to set the `component`s element to. * * @return {component} * returns itself; method can be chained. */ component.prototype.dimensions = function dimensions(width, height) { // skip resize listeners on width for optimization return this.width(width, true).height(height); }; /** * get or set width or height of the `component` element. this is the shared code * for the {@link component#width} and {@link component#height}. * * things to know: * - if the width or height in an number this will return the number postfixed with 'px'. * - if the width/height is a percent this will return the percent postfixed with '%' * - hidden elements have a width of 0 with `window.getcomputedstyle`. this function * defaults to the `component`s `style.width` and falls back to `window.getcomputedstyle`. * see [this]{@link http://www.foliotek.com/devblog/getting-the-width-of-a-hidden-element-with-jquery-using-width/} * for more information * - if you want the computed style of the component, use {@link component#currentwidth} * and {@link {component#currentheight} * * @fires component#resize * * @param {string} widthorheight 8 'width' or 'height' * * @param {number|string} [num] 8 new dimension * * @param {boolean} [skiplisteners] * skip resize event trigger * * @return {component} * - the dimension when getting or 0 if unset * - returns itself when setting; method can be chained. */ component.prototype.dimension = function dimension(widthorheight, num, skiplisteners) { if (num !== undefined) { // set to zero if null or literally nan (nan !== nan) if (num === null || num !== num) { num = 0; } // check if using css width/height (% or px) and adjust if (('' + num).indexof('%') !== -1 || ('' + num).indexof('px') !== -1) { this.el_.style[widthorheight] = num; } else if (num === 'auto') { this.el_.style[widthorheight] = ''; } else { this.el_.style[widthorheight] = num + 'px'; } // skiplisteners allows us to avoid triggering the resize event when setting both width and height if (!skiplisteners) { /** * triggered when a component is resized. * * @event component#resize * @type {eventtarget~event} */ this.trigger('resize'); } // return component return this; } // not setting a value, so getting it // make sure element exists if (!this.el_) { return 0; } // get dimension value from style var val = this.el_.style[widthorheight]; var pxindex = val.indexof('px'); if (pxindex !== -1) { // return the pixel value with no 'px' return parseint(val.slice(0, pxindex), 10); } // no px so using % or no style was set, so falling back to offsetwidth/height // if component has display:none, offset will return 0 // todo: handle display:none and no dimension style using px return parseint(this.el_['offset' + (0, _totitlecase2['default'])(widthorheight)], 10); }; /** * get the width or the height of the `component` elements computed style. uses * `window.getcomputedstyle`. * * @param {string} widthorheight * a string containing 'width' or 'height'. whichever one you want to get. * * @return {number} * the dimension that gets asked for or 0 if nothing was set * for that dimension. */ component.prototype.currentdimension = function currentdimension(widthorheight) { var computedwidthorheight = 0; if (widthorheight !== 'width' && widthorheight !== 'height') { throw new error('currentdimension only accepts width or height value'); } if (typeof _window2['default'].getcomputedstyle === 'function') { var computedstyle = _window2['default'].getcomputedstyle(this.el_); computedwidthorheight = computedstyle.getpropertyvalue(widthorheight) || computedstyle[widthorheight]; } // remove 'px' from variable and parse as integer computedwidthorheight = parsefloat(computedwidthorheight); // if the computed value is still 0, it's possible that the browser is lying // and we want to check the offset values. // this code also runs on ie8 and wherever getcomputedstyle doesn't exist. if (computedwidthorheight === 0) { var rule = 'offset' + (0, _totitlecase2['default'])(widthorheight); computedwidthorheight = this.el_[rule]; } return computedwidthorheight; }; /** * an object that contains width and height values of the `component`s * computed style. uses `window.getcomputedstyle`. * * @typedef {object} component~dimensionobject * * @property {number} width * the width of the `component`s computed style. * * @property {number} height * the height of the `component`s computed style. */ /** * get an object that contains width and height values of the `component`s * computed style. * * @return {component~dimensionobject} * the dimensions of the components element */ component.prototype.currentdimensions = function currentdimensions() { return { width: this.currentdimension('width'), height: this.currentdimension('height') }; }; /** * get the width of the `component`s computed style. uses `window.getcomputedstyle`. * * @return {number} width * the width of the `component`s computed style. */ component.prototype.currentwidth = function currentwidth() { return this.currentdimension('width'); }; /** * get the height of the `component`s computed style. uses `window.getcomputedstyle`. * * @return {number} height * the height of the `component`s computed style. */ component.prototype.currentheight = function currentheight() { return this.currentdimension('height'); }; /** * set the focus to this component */ component.prototype.focus = function focus() { this.el_.focus(); }; /** * remove the focus from this component */ component.prototype.blur = function blur() { this.el_.blur(); }; /** * emit a 'tap' events when touch event support gets detected. this gets used to * support toggling the controls through a tap on the video. they get enabled * because every sub-component would have extra overhead otherwise. * * @private * @fires component#tap * @listens component#touchstart * @listens component#touchmove * @listens component#touchleave * @listens component#touchcancel * @listens component#touchend */ component.prototype.emittapevents = function emittapevents() { // track the start time so we can determine how long the touch lasted var touchstart = 0; var firsttouch = null; // maximum movement allowed during a touch event to still be considered a tap // other popular libs use anywhere from 2 (hammer.js) to 15, // so 10 seems like a nice, round number. var tapmovementthreshold = 10; // the maximum length a touch can be while still being considered a tap var touchtimethreshold = 200; var couldbetap = void 0; this.on('touchstart', function (event) { // if more than one finger, don't consider treating this as a click if (event.touches.length === 1) { // copy pagex/pagey from the object firsttouch = { pagex: event.touches[0].pagex, pagey: event.touches[0].pagey }; // record start time so we can detect a tap vs. "touch and hold" touchstart = new date().gettime(); // reset couldbetap tracking couldbetap = true; } }); this.on('touchmove', function (event) { // if more than one finger, don't consider treating this as a click if (event.touches.length > 1) { couldbetap = false; } else if (firsttouch) { // some devices will throw touchmoves for all but the slightest of taps. // so, if we moved only a small distance, this could still be a tap var xdiff = event.touches[0].pagex - firsttouch.pagex; var ydiff = event.touches[0].pagey - firsttouch.pagey; var touchdistance = math.sqrt(xdiff * xdiff + ydiff * ydiff); if (touchdistance > tapmovementthreshold) { couldbetap = false; } } }); var notap = function notap() { couldbetap = false; }; // todo: listen to the original target. http://youtu.be/dujfpxokup8?t=13m8s this.on('touchleave', notap); this.on('touchcancel', notap); // when the touch ends, measure how long it took and trigger the appropriate // event this.on('touchend', function (event) { firsttouch = null; // proceed only if the touchmove/leave/cancel event didn't happen if (couldbetap === true) { // measure how long the touch lasted var touchtime = new date().gettime() - touchstart; // make sure the touch was less than the threshold to be considered a tap if (touchtime < touchtimethreshold) { // don't let browser turn this into a click event.preventdefault(); /** * triggered when a `component` is tapped. * * @event component#tap * @type {eventtarget~event} */ this.trigger('tap'); // it may be good to copy the touchend event object and change the // type to tap, if the other event properties aren't exact after // events.fixevent runs (e.g. event.target) } } }); }; /** * this function reports user activity whenever touch events happen. this can get * turned off by any sub-components that wants touch events to act another way. * * report user touch activity when touch events occur. user activity gets used to * determine when controls should show/hide. it is simple when it comes to mouse * events, because any mouse event should show the controls. so we capture mouse * events that bubble up to the player and report activity when that happens. * with touch events it isn't as easy as `touchstart` and `touchend` toggle player * controls. so touch events can't help us at the player level either. * * user activity gets checked asynchronously. so what could happen is a tap event * on the video turns the controls off. then the `touchend` event bubbles up to * the player. which, if it reported user activity, would turn the controls right * back on. we also don't want to completely block touch events from bubbling up. * furthermore a `touchmove` event and anything other than a tap, should not turn * controls back on. * * @listens component#touchstart * @listens component#touchmove * @listens component#touchend * @listens component#touchcancel */ component.prototype.enabletouchactivity = function enabletouchactivity() { // don't continue if the root player doesn't support reporting user activity if (!this.player() || !this.player().reportuseractivity) { return; } // listener for reporting that the user is active var report = fn.bind(this.player(), this.player().reportuseractivity); var touchholding = void 0; this.on('touchstart', function () { report(); // for as long as the they are touching the device or have their mouse down, // we consider them active even if they're not moving their finger or mouse. // so we want to continue to update that they are active this.clearinterval(touchholding); // report at the same interval as activitycheck touchholding = this.setinterval(report, 250); }); var touchend = function touchend(event) { report(); // stop the interval that maintains activity if the touch is holding this.clearinterval(touchholding); }; this.on('touchmove', report); this.on('touchend', touchend); this.on('touchcancel', touchend); }; /** * a callback that has no parameters and is bound into `component`s context. * * @callback component~genericcallback * @this component */ /** * creates a function that runs after an `x` millisecond timeout. this function is a * wrapper around `window.settimeout`. there are a few reasons to use this one * instead though: * 1. it gets cleared via {@link component#cleartimeout} when * {@link component#dispose} gets called. * 2. the function callback will gets turned into a {@link component~genericcallback} * * > note: you can use `window.cleartimeout` on the id returned by this function. this * will cause its dispose listener not to get cleaned up! please use * {@link component#cleartimeout} or {@link component#dispose}. * * @param {component~genericcallback} fn * the function that will be run after `timeout`. * * @param {number} timeout * timeout in milliseconds to delay before executing the specified function. * * @return {number} * returns a timeout id that gets used to identify the timeout. it can also * get used in {@link component#cleartimeout} to clear the timeout that * was set. * * @listens component#dispose * @see [similar to]{@link https://developer.mozilla.org/en-us/docs/web/api/windowtimers/settimeout} */ component.prototype.settimeout = function settimeout(fn, timeout) { fn = fn.bind(this, fn); var timeoutid = _window2['default'].settimeout(fn, timeout); var disposefn = function disposefn() { this.cleartimeout(timeoutid); }; disposefn.guid = 'vjs-timeout-' + timeoutid; this.on('dispose', disposefn); return timeoutid; }; /** * clears a timeout that gets created via `window.settimeout` or * {@link component#settimeout}. if you set a timeout via {@link component#settimeout} * use this function instead of `window.cleartimout`. if you don't your dispose * listener will not get cleaned up until {@link component#dispose}! * * @param {number} timeoutid * the id of the timeout to clear. the return value of * {@link component#settimeout} or `window.settimeout`. * * @return {number} * returns the timeout id that was cleared. * * @see [similar to]{@link https://developer.mozilla.org/en-us/docs/web/api/windowtimers/cleartimeout} */ component.prototype.cleartimeout = function cleartimeout(timeoutid) { _window2['default'].cleartimeout(timeoutid); var disposefn = function disposefn() {}; disposefn.guid = 'vjs-timeout-' + timeoutid; this.off('dispose', disposefn); return timeoutid; }; /** * creates a function that gets run every `x` milliseconds. this function is a wrapper * around `window.setinterval`. there are a few reasons to use this one instead though. * 1. it gets cleared via {@link component#clearinterval} when * {@link component#dispose} gets called. * 2. the function callback will be a {@link component~genericcallback} * * @param {component~genericcallback} fn * the function to run every `x` seconds. * * @param {number} interval * execute the specified function every `x` milliseconds. * * @return {number} * returns an id that can be used to identify the interval. it can also be be used in * {@link component#clearinterval} to clear the interval. * * @listens component#dispose * @see [similar to]{@link https://developer.mozilla.org/en-us/docs/web/api/windowtimers/setinterval} */ component.prototype.setinterval = function setinterval(fn, interval) { fn = fn.bind(this, fn); var intervalid = _window2['default'].setinterval(fn, interval); var disposefn = function disposefn() { this.clearinterval(intervalid); }; disposefn.guid = 'vjs-interval-' + intervalid; this.on('dispose', disposefn); return intervalid; }; /** * clears an interval that gets created via `window.setinterval` or * {@link component#setinterval}. if you set an inteval via {@link component#setinterval} * use this function instead of `window.clearinterval`. if you don't your dispose * listener will not get cleaned up until {@link component#dispose}! * * @param {number} intervalid * the id of the interval to clear. the return value of * {@link component#setinterval} or `window.setinterval`. * * @return {number} * returns the interval id that was cleared. * * @see [similar to]{@link https://developer.mozilla.org/en-us/docs/web/api/windowtimers/clearinterval} */ component.prototype.clearinterval = function clearinterval(intervalid) { _window2['default'].clearinterval(intervalid); var disposefn = function disposefn() {}; disposefn.guid = 'vjs-interval-' + intervalid; this.off('dispose', disposefn); return intervalid; }; /** * register a `component` with `videojs` given the name and the component. * * > note: {@link tech}s should not be registered as a `component`. {@link tech}s * should be registered using {@link tech.registertech} or * {@link videojs:videojs.registertech}. * * > note: this function can also be seen on videojs as * {@link videojs:videojs.registercomponent}. * * @param {string} name * the name of the `component` to register. * * @param {component} comp * the `component` class to register. * * @return {component} * the `component` that was registered. */ component.registercomponent = function registercomponent(name, comp) { if (!name) { return; } name = (0, _totitlecase2['default'])(name); if (!component.components_) { component.components_ = {}; } if (name === 'player' && component.components_[name]) { var player = component.components_[name]; // if we have players that were disposed, then their name will still be // in players.players. so, we must loop through and verify that the value // for each item is not null. this allows registration of the player component // after all players have been disposed or before any were created. if (player.players && object.keys(player.players).length > 0 && object.keys(player.players).map(function (playername) { return player.players[playername]; }).every(boolean)) { throw new error('can not register player component after player has been created'); } } component.components_[name] = comp; return comp; }; /** * get a `component` based on the name it was registered with. * * @param {string} name * the name of the component to get. * * @return {component} * the `component` that got registered under the given name. * * @deprecated in `videojs` 6 this will not return `component`s that were not * registered using {@link component.registercomponent}. currently we * check the global `videojs` object for a `component` name and * return that if it exists. */ component.getcomponent = function getcomponent(name) { if (!name) { return; } name = (0, _totitlecase2['default'])(name); if (component.components_ && component.components_[name]) { return component.components_[name]; } if (_window2['default'] && _window2['default'].videojs && _window2['default'].videojs[name]) { _log2['default'].warn('the ' + name + ' component was added to the videojs object when it should be registered using videojs.registercomponent(name, component)'); return _window2['default'].videojs[name]; } }; /** * sets up the constructor using the supplied init method or uses the init of the * parent object. * * @param {object} [props={}] * an object of properties. * * @return {object} * the extended object. * * @deprecated since version 5 */ component.extend = function extend(props) { props = props || {}; _log2['default'].warn('component.extend({}) has been deprecated, ' + ' use videojs.extend(component, {}) instead'); // set up the constructor using the supplied init method // or using the init of the parent object // make sure to check the unobfuscated version for external libs var init = props.init || props.init || this.prototype.init || this.prototype.init || function () {}; // in resig's simple class inheritance (previously used) the constructor // is a function that calls `this.init.apply(arguments)` // however that would prevent us from using `parentobject.call(this);` // in a child constructor because the `this` in `this.init` // would still refer to the child and cause an infinite loop. // we would instead have to do // `parentobject.prototype.init.apply(this, arguments);` // bleh. we're not creating a _super() function, so it's good to keep // the parent constructor reference simple. var subobj = function subobj() { init.apply(this, arguments); }; // inherit from this object's prototype subobj.prototype = object.create(this.prototype); // reset the constructor property for subobj otherwise // instances of subobj would have the constructor of the parent object subobj.prototype.constructor = subobj; // make the class extendable subobj.extend = component.extend; // extend subobj's prototype with functions and other properties from props for (var name in props) { if (props.hasownproperty(name)) { subobj.prototype[name] = props[name]; } } return subobj; }; return component; }(); component.registercomponent('component', component); exports['default'] = component; },{"81":81,"82":82,"83":83,"85":85,"86":86,"87":87,"91":91,"95":95}],6:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _trackbutton = _dereq_(36); var _trackbutton2 = _interoprequiredefault(_trackbutton); var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); var _audiotrackmenuitem = _dereq_(7); var _audiotrackmenuitem2 = _interoprequiredefault(_audiotrackmenuitem); function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file audio-track-button.js */ /** * the base class for buttons that toggle specific {@link audiotrack} types. * * @extends trackbutton */ var audiotrackbutton = function (_trackbutton) { _inherits(audiotrackbutton, _trackbutton); /** * creates an instance of this class. * * @param {player} player * the `player` that this class should be attached to. * * @param {object} [options={}] * the key/value store of player options. */ function audiotrackbutton(player) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; _classcallcheck(this, audiotrackbutton); options.tracks = player.audiotracks && player.audiotracks(); var _this = _possibleconstructorreturn(this, _trackbutton.call(this, player, options)); _this.el_.setattribute('aria-label', 'audio menu'); return _this; } /** * builds the default dom `classname`. * * @return {string} * the dom `classname` for this object. */ audiotrackbutton.prototype.buildcssclass = function buildcssclass() { return 'vjs-audio-button ' + _trackbutton.prototype.buildcssclass.call(this); }; /** * create a menu item for each audio track * * @param {audiotrackmenuitem[]} [items=[]] * an array of existing menu items to use. * * @return {audiotrackmenuitem[]} * an array of menu items */ audiotrackbutton.prototype.createitems = function createitems() { var items = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; // if there's only one audio track, there no point in showing it this.hidethreshold_ = 1; var tracks = this.player_.audiotracks && this.player_.audiotracks(); if (!tracks) { return items; } for (var i = 0; i < tracks.length; i++) { var track = tracks[i]; items.push(new _audiotrackmenuitem2['default'](this.player_, { track: track, // menuitem is selectable selectable: true })); } return items; }; return audiotrackbutton; }(_trackbutton2['default']); /** * the text that should display over the `audiotrackbutton`s controls. added for localization. * * @type {string} * @private */ audiotrackbutton.prototype.controltext_ = 'audio track'; _component2['default'].registercomponent('audiotrackbutton', audiotrackbutton); exports['default'] = audiotrackbutton; },{"36":36,"5":5,"7":7}],7:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _menuitem = _dereq_(48); var _menuitem2 = _interoprequiredefault(_menuitem); var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); var _fn = _dereq_(83); var fn = _interoprequirewildcard(_fn); function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file audio-track-menu-item.js */ /** * an {@link audiotrack} {@link menuitem} * * @extends menuitem */ var audiotrackmenuitem = function (_menuitem) { _inherits(audiotrackmenuitem, _menuitem); /** * creates an instance of this class. * * @param {player} player * the `player` that this class should be attached to. * * @param {object} [options] * the key/value store of player options. */ function audiotrackmenuitem(player, options) { _classcallcheck(this, audiotrackmenuitem); var track = options.track; var tracks = player.audiotracks(); // modify options for parent menuitem class's init. options.label = track.label || track.language || 'unknown'; options.selected = track.enabled; var _this = _possibleconstructorreturn(this, _menuitem.call(this, player, options)); _this.track = track; if (tracks) { var changehandler = fn.bind(_this, _this.handletrackschange); tracks.addeventlistener('change', changehandler); _this.on('dispose', function () { tracks.removeeventlistener('change', changehandler); }); } return _this; } /** * this gets called when an `audiotrackmenuitem is "clicked". see {@link clickablecomponent} * for more detailed information on what a click can be. * * @param {eventtarget~event} [event] * the `keydown`, `tap`, or `click` event that caused this function to be * called. * * @listens tap * @listens click */ audiotrackmenuitem.prototype.handleclick = function handleclick(event) { var tracks = this.player_.audiotracks(); _menuitem.prototype.handleclick.call(this, event); if (!tracks) { return; } for (var i = 0; i < tracks.length; i++) { var track = tracks[i]; track.enabled = track === this.track; } }; /** * handle any {@link audiotrack} change. * * @param {eventtarget~event} [event] * the {@link audiotracklist#change} event that caused this to run. * * @listens audiotracklist#change */ audiotrackmenuitem.prototype.handletrackschange = function handletrackschange(event) { this.selected(this.track.enabled); }; return audiotrackmenuitem; }(_menuitem2['default']); _component2['default'].registercomponent('audiotrackmenuitem', audiotrackmenuitem); exports['default'] = audiotrackmenuitem; },{"48":48,"5":5,"83":83}],8:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); _dereq_(12); _dereq_(32); _dereq_(33); _dereq_(35); _dereq_(34); _dereq_(10); _dereq_(18); _dereq_(9); _dereq_(38); _dereq_(40); _dereq_(11); _dereq_(25); _dereq_(27); _dereq_(29); _dereq_(24); _dereq_(6); _dereq_(13); _dereq_(21); function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file control-bar.js */ // required children /** * container of main controls. * * @extends component */ var controlbar = function (_component) { _inherits(controlbar, _component); function controlbar() { _classcallcheck(this, controlbar); return _possibleconstructorreturn(this, _component.apply(this, arguments)); } /** * create the `component`'s dom element * * @return {element} * the element that was created. */ controlbar.prototype.createel = function createel() { return _component.prototype.createel.call(this, 'div', { classname: 'vjs-control-bar', dir: 'ltr' }, { // the control bar is a group, so it can contain menuitems role: 'group' }); }; return controlbar; }(_component2['default']); /** * default options for `controlbar` * * @type {object} * @private */ controlbar.prototype.options_ = { children: ['playtoggle', 'volumemenubutton', 'currenttimedisplay', 'timedivider', 'durationdisplay', 'progresscontrol', 'livedisplay', 'remainingtimedisplay', 'customcontrolspacer', 'playbackratemenubutton', 'chaptersbutton', 'descriptionsbutton', 'subtitlesbutton', 'captionsbutton', 'audiotrackbutton', 'fullscreentoggle'] }; _component2['default'].registercomponent('controlbar', controlbar); exports['default'] = controlbar; },{"10":10,"11":11,"12":12,"13":13,"18":18,"21":21,"24":24,"25":25,"27":27,"29":29,"32":32,"33":33,"34":34,"35":35,"38":38,"40":40,"5":5,"6":6,"9":9}],9:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _button = _dereq_(2); var _button2 = _interoprequiredefault(_button); var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file fullscreen-toggle.js */ /** * toggle fullscreen video * * @extends button */ var fullscreentoggle = function (_button) { _inherits(fullscreentoggle, _button); /** * creates an instance of this class. * * @param {player} player * the `player` that this class should be attached to. * * @param {object} [options] * the key/value store of player options. */ function fullscreentoggle(player, options) { _classcallcheck(this, fullscreentoggle); var _this = _possibleconstructorreturn(this, _button.call(this, player, options)); _this.on(player, 'fullscreenchange', _this.handlefullscreenchange); return _this; } /** * builds the default dom `classname`. * * @return {string} * the dom `classname` for this object. */ fullscreentoggle.prototype.buildcssclass = function buildcssclass() { return 'vjs-fullscreen-control ' + _button.prototype.buildcssclass.call(this); }; /** * handles fullscreenchange on the player and change control text accordingly. * * @param {eventtarget~event} [event] * the {@link player#fullscreenchange} event that caused this function to be * called. * * @listens player#fullscreenchange */ fullscreentoggle.prototype.handlefullscreenchange = function handlefullscreenchange(event) { if (this.player_.isfullscreen()) { this.controltext('non-fullscreen'); } else { this.controltext('fullscreen'); } }; /** * this gets called when an `fullscreentoggle` is "clicked". see * {@link clickablecomponent} for more detailed information on what a click can be. * * @param {eventtarget~event} [event] * the `keydown`, `tap`, or `click` event that caused this function to be * called. * * @listens tap * @listens click */ fullscreentoggle.prototype.handleclick = function handleclick(event) { if (!this.player_.isfullscreen()) { this.player_.requestfullscreen(); } else { this.player_.exitfullscreen(); } }; return fullscreentoggle; }(_button2['default']); /** * the text that should display over the `fullscreentoggle`s controls. added for localization. * * @type {string} * @private */ fullscreentoggle.prototype.controltext_ = 'fullscreen'; _component2['default'].registercomponent('fullscreentoggle', fullscreentoggle); exports['default'] = fullscreentoggle; },{"2":2,"5":5}],10:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); var _dom = _dereq_(81); var dom = _interoprequirewildcard(_dom); function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file live-display.js */ // todo - future make it click to snap to live /** * displays the live indicator when duration is infinity. * * @extends component */ var livedisplay = function (_component) { _inherits(livedisplay, _component); /** * creates an instance of this class. * * @param {player} player * the `player` that this class should be attached to. * * @param {object} [options] * the key/value store of player options. */ function livedisplay(player, options) { _classcallcheck(this, livedisplay); var _this = _possibleconstructorreturn(this, _component.call(this, player, options)); _this.updateshowing(); _this.on(_this.player(), 'durationchange', _this.updateshowing); return _this; } /** * create the `component`'s dom element * * @return {element} * the element that was created. */ livedisplay.prototype.createel = function createel() { var el = _component.prototype.createel.call(this, 'div', { classname: 'vjs-live-control vjs-control' }); this.contentel_ = dom.createel('div', { classname: 'vjs-live-display', innerhtml: '' + this.localize('stream type') + '' + this.localize('live') }, { 'aria-live': 'off' }); el.appendchild(this.contentel_); return el; }; /** * check the duration to see if the livedisplay should be showing or not. then show/hide * it accordingly * * @param {eventtarget~event} [event] * the {@link player#durationchange} event that caused this function to run. * * @listens player#durationchange */ livedisplay.prototype.updateshowing = function updateshowing(event) { if (this.player().duration() === infinity) { this.show(); } else { this.hide(); } }; return livedisplay; }(_component2['default']); _component2['default'].registercomponent('livedisplay', livedisplay); exports['default'] = livedisplay; },{"5":5,"81":81}],11:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _button = _dereq_(2); var _button2 = _interoprequiredefault(_button); var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); var _dom = _dereq_(81); var dom = _interoprequirewildcard(_dom); function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file mute-toggle.js */ /** * a button component for muting the audio. * * @extends button */ var mutetoggle = function (_button) { _inherits(mutetoggle, _button); /** * creates an instance of this class. * * @param {player} player * the `player` that this class should be attached to. * * @param {object} [options] * the key/value store of player options. */ function mutetoggle(player, options) { _classcallcheck(this, mutetoggle); var _this = _possibleconstructorreturn(this, _button.call(this, player, options)); _this.on(player, 'volumechange', _this.update); // hide mute toggle if the current tech doesn't support volume control if (player.tech_ && player.tech_.featuresvolumecontrol === false) { _this.addclass('vjs-hidden'); } _this.on(player, 'loadstart', function () { // we need to update the button to account for a default muted state. this.update(); if (player.tech_.featuresvolumecontrol === false) { this.addclass('vjs-hidden'); } else { this.removeclass('vjs-hidden'); } }); return _this; } /** * builds the default dom `classname`. * * @return {string} * the dom `classname` for this object. */ mutetoggle.prototype.buildcssclass = function buildcssclass() { return 'vjs-mute-control ' + _button.prototype.buildcssclass.call(this); }; /** * this gets called when an `mutetoggle` is "clicked". see * {@link clickablecomponent} for more detailed information on what a click can be. * * @param {eventtarget~event} [event] * the `keydown`, `tap`, or `click` event that caused this function to be * called. * * @listens tap * @listens click */ mutetoggle.prototype.handleclick = function handleclick(event) { this.player_.muted(this.player_.muted() ? false : true); }; /** * update the state of volume. * * @param {eventtarget~event} [event] * the {@link player#loadstart} event if this function was called through an * event. * * @listens player#loadstart */ mutetoggle.prototype.update = function update(event) { var vol = this.player_.volume(); var level = 3; if (vol === 0 || this.player_.muted()) { level = 0; } else if (vol < 0.33) { level = 1; } else if (vol < 0.67) { level = 2; } // don't rewrite the button text if the actual text doesn't change. // this causes unnecessary and confusing information for screen reader users. // this check is needed because this function gets called every time the volume level is changed. var tomute = this.player_.muted() ? 'unmute' : 'mute'; if (this.controltext() !== tomute) { this.controltext(tomute); } // todo improve muted icon classes for (var i = 0; i < 4; i++) { dom.removeelclass(this.el_, 'vjs-vol-' + i); } dom.addelclass(this.el_, 'vjs-vol-' + level); }; return mutetoggle; }(_button2['default']); /** * the text that should display over the `mutetoggle`s controls. added for localization. * * @type {string} * @private */ mutetoggle.prototype.controltext_ = 'mute'; _component2['default'].registercomponent('mutetoggle', mutetoggle); exports['default'] = mutetoggle; },{"2":2,"5":5,"81":81}],12:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _button = _dereq_(2); var _button2 = _interoprequiredefault(_button); var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file play-toggle.js */ /** * button to toggle between play and pause. * * @extends button */ var playtoggle = function (_button) { _inherits(playtoggle, _button); /** * creates an instance of this class. * * @param {player} player * the `player` that this class should be attached to. * * @param {object} [options] * the key/value store of player options. */ function playtoggle(player, options) { _classcallcheck(this, playtoggle); var _this = _possibleconstructorreturn(this, _button.call(this, player, options)); _this.on(player, 'play', _this.handleplay); _this.on(player, 'pause', _this.handlepause); return _this; } /** * builds the default dom `classname`. * * @return {string} * the dom `classname` for this object. */ playtoggle.prototype.buildcssclass = function buildcssclass() { return 'vjs-play-control ' + _button.prototype.buildcssclass.call(this); }; /** * this gets called when an `playtoggle` is "clicked". see * {@link clickablecomponent} for more detailed information on what a click can be. * * @param {eventtarget~event} [event] * the `keydown`, `tap`, or `click` event that caused this function to be * called. * * @listens tap * @listens click */ playtoggle.prototype.handleclick = function handleclick(event) { if (this.player_.paused()) { this.player_.play(); } else { this.player_.pause(); } }; /** * add the vjs-playing class to the element so it can change appearance. * * @param {eventtarget~event} [event] * the event that caused this function to run. * * @listens player#play */ playtoggle.prototype.handleplay = function handleplay(event) { this.removeclass('vjs-paused'); this.addclass('vjs-playing'); // change the button text to "pause" this.controltext('pause'); }; /** * add the vjs-paused class to the element so it can change appearance. * * @param {eventtarget~event} [event] * the event that caused this function to run. * * @listens player#pause */ playtoggle.prototype.handlepause = function handlepause(event) { this.removeclass('vjs-playing'); this.addclass('vjs-paused'); // change the button text to "play" this.controltext('play'); }; return playtoggle; }(_button2['default']); /** * the text that should display over the `playtoggle`s controls. added for localization. * * @type {string} * @private */ playtoggle.prototype.controltext_ = 'play'; _component2['default'].registercomponent('playtoggle', playtoggle); exports['default'] = playtoggle; },{"2":2,"5":5}],13:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _menubutton = _dereq_(47); var _menubutton2 = _interoprequiredefault(_menubutton); var _menu = _dereq_(49); var _menu2 = _interoprequiredefault(_menu); var _playbackratemenuitem = _dereq_(14); var _playbackratemenuitem2 = _interoprequiredefault(_playbackratemenuitem); var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); var _dom = _dereq_(81); var dom = _interoprequirewildcard(_dom); function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file playback-rate-menu-button.js */ /** * the component for controlling the playback rate. * * @extends menubutton */ var playbackratemenubutton = function (_menubutton) { _inherits(playbackratemenubutton, _menubutton); /** * creates an instance of this class. * * @param {player} player * the `player` that this class should be attached to. * * @param {object} [options] * the key/value store of player options. */ function playbackratemenubutton(player, options) { _classcallcheck(this, playbackratemenubutton); var _this = _possibleconstructorreturn(this, _menubutton.call(this, player, options)); _this.updatevisibility(); _this.updatelabel(); _this.on(player, 'loadstart', _this.updatevisibility); _this.on(player, 'ratechange', _this.updatelabel); return _this; } /** * create the `component`'s dom element * * @return {element} * the element that was created. */ playbackratemenubutton.prototype.createel = function createel() { var el = _menubutton.prototype.createel.call(this); this.labelel_ = dom.createel('div', { classname: 'vjs-playback-rate-value', innerhtml: 1.0 }); el.appendchild(this.labelel_); return el; }; /** * builds the default dom `classname`. * * @return {string} * the dom `classname` for this object. */ playbackratemenubutton.prototype.buildcssclass = function buildcssclass() { return 'vjs-playback-rate ' + _menubutton.prototype.buildcssclass.call(this); }; /** * create the playback rate menu * * @return {menu} * menu object populated with {@link playbackratemenuitem}s */ playbackratemenubutton.prototype.createmenu = function createmenu() { var menu = new _menu2['default'](this.player()); var rates = this.playbackrates(); if (rates) { for (var i = rates.length - 1; i >= 0; i--) { menu.addchild(new _playbackratemenuitem2['default'](this.player(), { rate: rates[i] + 'x' })); } } return menu; }; /** * updates aria accessibility attributes */ playbackratemenubutton.prototype.updateariaattributes = function updateariaattributes() { // current playback rate this.el().setattribute('aria-valuenow', this.player().playbackrate()); }; /** * this gets called when an `playbackratemenubutton` is "clicked". see * {@link clickablecomponent} for more detailed information on what a click can be. * * @param {eventtarget~event} [event] * the `keydown`, `tap`, or `click` event that caused this function to be * called. * * @listens tap * @listens click */ playbackratemenubutton.prototype.handleclick = function handleclick(event) { // select next rate option var currentrate = this.player().playbackrate(); var rates = this.playbackrates(); // this will select first one if the last one currently selected var newrate = rates[0]; for (var i = 0; i < rates.length; i++) { if (rates[i] > currentrate) { newrate = rates[i]; break; } } this.player().playbackrate(newrate); }; /** * get possible playback rates * * @return {array} * all possible playback rates */ playbackratemenubutton.prototype.playbackrates = function playbackrates() { return this.options_.playbackrates || this.options_.playeroptions && this.options_.playeroptions.playbackrates; }; /** * get whether playback rates is supported by the tech * and an array of playback rates exists * * @return {boolean} * whether changing playback rate is supported */ playbackratemenubutton.prototype.playbackratesupported = function playbackratesupported() { return this.player().tech_ && this.player().tech_.featuresplaybackrate && this.playbackrates() && this.playbackrates().length > 0; }; /** * hide playback rate controls when they're no playback rate options to select * * @param {eventtarget~event} [event] * the event that caused this function to run. * * @listens player#loadstart */ playbackratemenubutton.prototype.updatevisibility = function updatevisibility(event) { if (this.playbackratesupported()) { this.removeclass('vjs-hidden'); } else { this.addclass('vjs-hidden'); } }; /** * update button label when rate changed * * @param {eventtarget~event} [event] * the event that caused this function to run. * * @listens player#ratechange */ playbackratemenubutton.prototype.updatelabel = function updatelabel(event) { if (this.playbackratesupported()) { this.labelel_.innerhtml = this.player().playbackrate() + 'x'; } }; return playbackratemenubutton; }(_menubutton2['default']); /** * the text that should display over the `fullscreentoggle`s controls. added for localization. * * @type {string} * @private */ playbackratemenubutton.prototype.controltext_ = 'playback rate'; _component2['default'].registercomponent('playbackratemenubutton', playbackratemenubutton); exports['default'] = playbackratemenubutton; },{"14":14,"47":47,"49":49,"5":5,"81":81}],14:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _menuitem = _dereq_(48); var _menuitem2 = _interoprequiredefault(_menuitem); var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file playback-rate-menu-item.js */ /** * the specific menu item type for selecting a playback rate. * * @extends menuitem */ var playbackratemenuitem = function (_menuitem) { _inherits(playbackratemenuitem, _menuitem); /** * creates an instance of this class. * * @param {player} player * the `player` that this class should be attached to. * * @param {object} [options] * the key/value store of player options. */ function playbackratemenuitem(player, options) { _classcallcheck(this, playbackratemenuitem); var label = options.rate; var rate = parsefloat(label, 10); // modify options for parent menuitem class's init. options.label = label; options.selected = rate === 1; options.selectable = true; var _this = _possibleconstructorreturn(this, _menuitem.call(this, player, options)); _this.label = label; _this.rate = rate; _this.on(player, 'ratechange', _this.update); return _this; } /** * this gets called when an `playbackratemenuitem` is "clicked". see * {@link clickablecomponent} for more detailed information on what a click can be. * * @param {eventtarget~event} [event] * the `keydown`, `tap`, or `click` event that caused this function to be * called. * * @listens tap * @listens click */ playbackratemenuitem.prototype.handleclick = function handleclick(event) { _menuitem.prototype.handleclick.call(this); this.player().playbackrate(this.rate); }; /** * update the playbackratemenuitem when the playbackrate changes. * * @param {eventtarget~event} [event] * the `ratechange` event that caused this function to run. * * @listens player#ratechange */ playbackratemenuitem.prototype.update = function update(event) { this.selected(this.player().playbackrate() === this.rate); }; return playbackratemenuitem; }(_menuitem2['default']); /** * the text that should display over the `playbackratemenuitem`s controls. added for localization. * * @type {string} * @private */ playbackratemenuitem.prototype.contenteltype = 'button'; _component2['default'].registercomponent('playbackratemenuitem', playbackratemenuitem); exports['default'] = playbackratemenuitem; },{"48":48,"5":5}],15:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); var _dom = _dereq_(81); var dom = _interoprequirewildcard(_dom); function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file load-progress-bar.js */ /** * shows loading progress * * @extends component */ var loadprogressbar = function (_component) { _inherits(loadprogressbar, _component); /** * creates an instance of this class. * * @param {player} player * the `player` that this class should be attached to. * * @param {object} [options] * the key/value store of player options. */ function loadprogressbar(player, options) { _classcallcheck(this, loadprogressbar); var _this = _possibleconstructorreturn(this, _component.call(this, player, options)); _this.partels_ = []; _this.on(player, 'progress', _this.update); return _this; } /** * create the `component`'s dom element * * @return {element} * the element that was created. */ loadprogressbar.prototype.createel = function createel() { return _component.prototype.createel.call(this, 'div', { classname: 'vjs-load-progress', innerhtml: '' + this.localize('loaded') + ': 0%' }); }; /** * update progress bar * * @param {eventtarget~event} [event] * the `progress` event that caused this function to run. * * @listens player#progress */ loadprogressbar.prototype.update = function update(event) { var buffered = this.player_.buffered(); var duration = this.player_.duration(); var bufferedend = this.player_.bufferedend(); var children = this.partels_; // get the percent width of a time compared to the total end var percentify = function percentify(time, end) { // no nan var percent = time / end || 0; return (percent >= 1 ? 1 : percent) * 100 + '%'; }; // update the width of the progress bar this.el_.style.width = percentify(bufferedend, duration); // add child elements to represent the individual buffered time ranges for (var i = 0; i < buffered.length; i++) { var start = buffered.start(i); var end = buffered.end(i); var part = children[i]; if (!part) { part = this.el_.appendchild(dom.createel()); children[i] = part; } // set the percent based on the width of the progress bar (bufferedend) part.style.left = percentify(start, bufferedend); part.style.width = percentify(end - start, bufferedend); } // remove unused buffered range elements for (var _i = children.length; _i > buffered.length; _i--) { this.el_.removechild(children[_i - 1]); } children.length = buffered.length; }; return loadprogressbar; }(_component2['default']); _component2['default'].registercomponent('loadprogressbar', loadprogressbar); exports['default'] = loadprogressbar; },{"5":5,"81":81}],16:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); var _dom = _dereq_(81); var dom = _interoprequirewildcard(_dom); var _fn = _dereq_(83); var fn = _interoprequirewildcard(_fn); var _formattime = _dereq_(84); var _formattime2 = _interoprequiredefault(_formattime); var _computedstyle = _dereq_(80); var _computedstyle2 = _interoprequiredefault(_computedstyle); function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file mouse-time-display.js */ /** * the mouse time display component shows the time you will seek to * when hovering over the progress bar * * @extends component */ var mousetimedisplay = function (_component) { _inherits(mousetimedisplay, _component); /** * creates an instance of this class. * * @param {player} player * the `player` that this class should be attached to. * * @param {object} [options] * the key/value store of player options. */ function mousetimedisplay(player, options) { _classcallcheck(this, mousetimedisplay); var _this = _possibleconstructorreturn(this, _component.call(this, player, options)); if (options.playeroptions && options.playeroptions.controlbar && options.playeroptions.controlbar.progresscontrol && options.playeroptions.controlbar.progresscontrol.keeptooltipsinside) { _this.keeptooltipsinside = options.playeroptions.controlbar.progresscontrol.keeptooltipsinside; } if (_this.keeptooltipsinside) { _this.tooltip = dom.createel('div', { classname: 'vjs-time-tooltip' }); _this.el().appendchild(_this.tooltip); _this.addclass('vjs-keep-tooltips-inside'); } _this.update(0, 0); player.on('ready', function () { _this.on(player.controlbar.progresscontrol.el(), 'mousemove', fn.throttle(fn.bind(_this, _this.handlemousemove), 25)); }); return _this; } /** * create the `component`'s dom element * * @return {element} * the element that was created. */ mousetimedisplay.prototype.createel = function createel() { return _component.prototype.createel.call(this, 'div', { classname: 'vjs-mouse-display' }); }; /** * handle the mouse move event on the `mousetimedisplay`. * * @param {eventtarget~event} event * the `mousemove` event that caused this to event to run. * * @listen mousemove */ mousetimedisplay.prototype.handlemousemove = function handlemousemove(event) { var duration = this.player_.duration(); var newtime = this.calculatedistance(event) * duration; var position = event.pagex - dom.findelposition(this.el().parentnode).left; this.update(newtime, position); }; /** * update the time and posistion of the `mousetimedisplay`. * * @param {number} newtime * time to change the `mousetimedisplay` to. * * @param {nubmer} position * postion from the left of the in pixels. */ mousetimedisplay.prototype.update = function update(newtime, position) { var time = (0, _formattime2['default'])(newtime, this.player_.duration()); this.el().style.left = position + 'px'; this.el().setattribute('data-current-time', time); if (this.keeptooltipsinside) { var clampedposition = this.clampposition_(position); var difference = position - clampedposition + 1; var tooltipwidth = parsefloat((0, _computedstyle2['default'])(this.tooltip, 'width')); var tooltipwidthhalf = tooltipwidth / 2; this.tooltip.innerhtml = time; this.tooltip.style.right = '-' + (tooltipwidthhalf - difference) + 'px'; } }; /** * get the mouse pointers x coordinate in pixels. * * @param {eventtarget~event} [event] * the `mousemove` event that was passed to this function by * {@link mousetimedisplay#handlemousemove} * * @return {number} * the x position in pixels of the mouse pointer. */ mousetimedisplay.prototype.calculatedistance = function calculatedistance(event) { return dom.getpointerposition(this.el().parentnode, event).x; }; /** * this takes in a horizontal position for the bar and returns a clamped position. * clamped position means that it will keep the position greater than half the width * of the tooltip and smaller than the player width minus half the width o the tooltip. * it will only clamp the position if `keeptooltipsinside` option is set. * * @param {number} position * the position the bar wants to be * * @return {number} * the (potentially) new clamped position. * * @private */ mousetimedisplay.prototype.clampposition_ = function clampposition_(position) { if (!this.keeptooltipsinside) { return position; } var playerwidth = parsefloat((0, _computedstyle2['default'])(this.player().el(), 'width')); var tooltipwidth = parsefloat((0, _computedstyle2['default'])(this.tooltip, 'width')); var tooltipwidthhalf = tooltipwidth / 2; var actualposition = position; if (position < tooltipwidthhalf) { actualposition = math.ceil(tooltipwidthhalf); } else if (position > playerwidth - tooltipwidthhalf) { actualposition = math.floor(playerwidth - tooltipwidthhalf); } return actualposition; }; return mousetimedisplay; }(_component2['default']); _component2['default'].registercomponent('mousetimedisplay', mousetimedisplay); exports['default'] = mousetimedisplay; },{"5":5,"80":80,"81":81,"83":83,"84":84}],17:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); var _fn = _dereq_(83); var fn = _interoprequirewildcard(_fn); var _formattime = _dereq_(84); var _formattime2 = _interoprequiredefault(_formattime); function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file play-progress-bar.js */ /** * shows play progress * * @extends component */ var playprogressbar = function (_component) { _inherits(playprogressbar, _component); /** * creates an instance of this class. * * @param {player} player * the `player` that this class should be attached to. * * @param {object} [options] * the key/value store of player options. */ function playprogressbar(player, options) { _classcallcheck(this, playprogressbar); var _this = _possibleconstructorreturn(this, _component.call(this, player, options)); _this.updatedataattr(); _this.on(player, 'timeupdate', _this.updatedataattr); player.ready(fn.bind(_this, _this.updatedataattr)); if (options.playeroptions && options.playeroptions.controlbar && options.playeroptions.controlbar.progresscontrol && options.playeroptions.controlbar.progresscontrol.keeptooltipsinside) { _this.keeptooltipsinside = options.playeroptions.controlbar.progresscontrol.keeptooltipsinside; } if (_this.keeptooltipsinside) { _this.addclass('vjs-keep-tooltips-inside'); } return _this; } /** * create the `component`'s dom element * * @return {element} * the element that was created. */ playprogressbar.prototype.createel = function createel() { return _component.prototype.createel.call(this, 'div', { classname: 'vjs-play-progress vjs-slider-bar', innerhtml: '' + this.localize('progress') + ': 0%' }); }; /** * update the data-current-time attribute on the `playprogressbar`. * * @param {eventtarget~event} [event] * the `timeupdate` event that caused this to run. * * @listens player#timeupdate */ playprogressbar.prototype.updatedataattr = function updatedataattr(event) { var time = this.player_.scrubbing() ? this.player_.getcache().currenttime : this.player_.currenttime(); this.el_.setattribute('data-current-time', (0, _formattime2['default'])(time, this.player_.duration())); }; return playprogressbar; }(_component2['default']); _component2['default'].registercomponent('playprogressbar', playprogressbar); exports['default'] = playprogressbar; },{"5":5,"83":83,"84":84}],18:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); _dereq_(19); _dereq_(16); function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file progress-control.js */ /** * the progress control component contains the seek bar, load progress, * and play progress. * * @extends component */ var progresscontrol = function (_component) { _inherits(progresscontrol, _component); function progresscontrol() { _classcallcheck(this, progresscontrol); return _possibleconstructorreturn(this, _component.apply(this, arguments)); } /** * create the `component`'s dom element * * @return {element} * the element that was created. */ progresscontrol.prototype.createel = function createel() { return _component.prototype.createel.call(this, 'div', { classname: 'vjs-progress-control vjs-control' }); }; return progresscontrol; }(_component2['default']); /** * default options for `progresscontrol` * * @type {object} * @private */ progresscontrol.prototype.options_ = { children: ['seekbar'] }; _component2['default'].registercomponent('progresscontrol', progresscontrol); exports['default'] = progresscontrol; },{"16":16,"19":19,"5":5}],19:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _slider = _dereq_(57); var _slider2 = _interoprequiredefault(_slider); var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); var _fn = _dereq_(83); var fn = _interoprequirewildcard(_fn); var _formattime = _dereq_(84); var _formattime2 = _interoprequiredefault(_formattime); var _computedstyle = _dereq_(80); var _computedstyle2 = _interoprequiredefault(_computedstyle); _dereq_(15); _dereq_(17); _dereq_(20); function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file seek-bar.js */ /** * seek bar and holder for the progress bars * * @extends slider */ var seekbar = function (_slider) { _inherits(seekbar, _slider); /** * creates an instance of this class. * * @param {player} player * the `player` that this class should be attached to. * * @param {object} [options] * the key/value store of player options. */ function seekbar(player, options) { _classcallcheck(this, seekbar); var _this = _possibleconstructorreturn(this, _slider.call(this, player, options)); _this.on(player, 'timeupdate', _this.updateprogress); _this.on(player, 'ended', _this.updateprogress); player.ready(fn.bind(_this, _this.updateprogress)); if (options.playeroptions && options.playeroptions.controlbar && options.playeroptions.controlbar.progresscontrol && options.playeroptions.controlbar.progresscontrol.keeptooltipsinside) { _this.keeptooltipsinside = options.playeroptions.controlbar.progresscontrol.keeptooltipsinside; } if (_this.keeptooltipsinside) { _this.tooltipprogressbar = _this.addchild('tooltipprogressbar'); } return _this; } /** * create the `component`'s dom element * * @return {element} * the element that was created. */ seekbar.prototype.createel = function createel() { return _slider.prototype.createel.call(this, 'div', { classname: 'vjs-progress-holder' }, { 'aria-label': 'progress bar' }); }; /** * update the seek bars tooltip and width. * * @param {eventtarget~event} [event] * the `timeupdate` or `ended` event that caused this to run. * * @listens player#timeupdate * @listens player#ended */ seekbar.prototype.updateprogress = function updateprogress(event) { this.updateariaattributes(this.el_); if (this.keeptooltipsinside) { this.updateariaattributes(this.tooltipprogressbar.el_); this.tooltipprogressbar.el_.style.width = this.bar.el_.style.width; var playerwidth = parsefloat((0, _computedstyle2['default'])(this.player().el(), 'width')); var tooltipwidth = parsefloat((0, _computedstyle2['default'])(this.tooltipprogressbar.tooltip, 'width')); var tooltipstyle = this.tooltipprogressbar.el().style; tooltipstyle.maxwidth = math.floor(playerwidth - tooltipwidth / 2) + 'px'; tooltipstyle.minwidth = math.ceil(tooltipwidth / 2) + 'px'; tooltipstyle.right = '-' + tooltipwidth / 2 + 'px'; } }; /** * update aria accessibility attributes * * @param {element} el * the element to update with aria accessibility attributes. */ seekbar.prototype.updateariaattributes = function updateariaattributes(el) { // allows for smooth scrubbing, when player can't keep up. var time = this.player_.scrubbing() ? this.player_.getcache().currenttime : this.player_.currenttime(); // machine readable value of progress bar (percentage complete) el.setattribute('aria-valuenow', (this.getpercent() * 100).tofixed(2)); // human readable value of progress bar (time complete) el.setattribute('aria-valuetext', (0, _formattime2['default'])(time, this.player_.duration())); }; /** * get percentage of video played * * @return {number} * the percentage played */ seekbar.prototype.getpercent = function getpercent() { var percent = this.player_.currenttime() / this.player_.duration(); return percent >= 1 ? 1 : percent; }; /** * handle mouse down on seek bar * * @param {eventtarget~event} event * the `mousedown` event that caused this to run. * * @listens mousedown */ seekbar.prototype.handlemousedown = function handlemousedown(event) { this.player_.scrubbing(true); this.videowasplaying = !this.player_.paused(); this.player_.pause(); _slider.prototype.handlemousedown.call(this, event); }; /** * handle mouse move on seek bar * * @param {eventtarget~event} event * the `mousemove` event that caused this to run. * * @listens mousemove */ seekbar.prototype.handlemousemove = function handlemousemove(event) { var newtime = this.calculatedistance(event) * this.player_.duration(); // don't let video end while scrubbing. if (newtime === this.player_.duration()) { newtime = newtime - 0.1; } // set new time (tell player to seek to new time) this.player_.currenttime(newtime); }; /** * handle mouse up on seek bar * * @param {eventtarget~event} event * the `mouseup` event that caused this to run. * * @listens mouseup */ seekbar.prototype.handlemouseup = function handlemouseup(event) { _slider.prototype.handlemouseup.call(this, event); this.player_.scrubbing(false); if (this.videowasplaying) { this.player_.play(); } }; /** * move more quickly fast forward for keyboard-only users */ seekbar.prototype.stepforward = function stepforward() { // more quickly fast forward for keyboard-only users this.player_.currenttime(this.player_.currenttime() + 5); }; /** * move more quickly rewind for keyboard-only users */ seekbar.prototype.stepback = function stepback() { // more quickly rewind for keyboard-only users this.player_.currenttime(this.player_.currenttime() - 5); }; return seekbar; }(_slider2['default']); /** * default options for the `seekbar` * * @type {object} * @private */ seekbar.prototype.options_ = { children: ['loadprogressbar', 'mousetimedisplay', 'playprogressbar'], barname: 'playprogressbar' }; /** * call the update event for this slider when this event happens on the player. * * @type {string} */ seekbar.prototype.playerevent = 'timeupdate'; _component2['default'].registercomponent('seekbar', seekbar); exports['default'] = seekbar; },{"15":15,"17":17,"20":20,"5":5,"57":57,"80":80,"83":83,"84":84}],20:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); var _fn = _dereq_(83); var fn = _interoprequirewildcard(_fn); var _formattime = _dereq_(84); var _formattime2 = _interoprequiredefault(_formattime); function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file play-progress-bar.js */ /** * shows play progress * * @extends component */ var tooltipprogressbar = function (_component) { _inherits(tooltipprogressbar, _component); /** * creates an instance of this class. * * @param {player} player * the `player` that this class should be attached to. * * @param {object} [options] * the key/value store of player options. */ function tooltipprogressbar(player, options) { _classcallcheck(this, tooltipprogressbar); var _this = _possibleconstructorreturn(this, _component.call(this, player, options)); _this.updatedataattr(); _this.on(player, 'timeupdate', _this.updatedataattr); player.ready(fn.bind(_this, _this.updatedataattr)); return _this; } /** * create the `component`'s dom element * * @return {element} * the element that was created. */ tooltipprogressbar.prototype.createel = function createel() { var el = _component.prototype.createel.call(this, 'div', { classname: 'vjs-tooltip-progress-bar vjs-slider-bar', innerhtml: '
\n ' + this.localize('progress') + ': 0%' }); this.tooltip = el.queryselector('.vjs-time-tooltip'); return el; }; /** * updatet the data-current-time attribute for tooltipprogressbar * * @param {eventtarget~event} [event] * the `timeupdate` event that caused this function to run. * * @listens player#timeupdate */ tooltipprogressbar.prototype.updatedataattr = function updatedataattr(event) { var time = this.player_.scrubbing() ? this.player_.getcache().currenttime : this.player_.currenttime(); var formattedtime = (0, _formattime2['default'])(time, this.player_.duration()); this.el_.setattribute('data-current-time', formattedtime); this.tooltip.innerhtml = formattedtime; }; return tooltipprogressbar; }(_component2['default']); _component2['default'].registercomponent('tooltipprogressbar', tooltipprogressbar); exports['default'] = tooltipprogressbar; },{"5":5,"83":83,"84":84}],21:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _spacer = _dereq_(22); var _spacer2 = _interoprequiredefault(_spacer); var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file custom-control-spacer.js */ /** * spacer specifically meant to be used as an insertion point for new plugins, etc. * * @extends spacer */ var customcontrolspacer = function (_spacer) { _inherits(customcontrolspacer, _spacer); function customcontrolspacer() { _classcallcheck(this, customcontrolspacer); return _possibleconstructorreturn(this, _spacer.apply(this, arguments)); } /** * builds the default dom `classname`. * * @return {string} * the dom `classname` for this object. */ customcontrolspacer.prototype.buildcssclass = function buildcssclass() { return 'vjs-custom-control-spacer ' + _spacer.prototype.buildcssclass.call(this); }; /** * create the `component`'s dom element * * @return {element} * the element that was created. */ customcontrolspacer.prototype.createel = function createel() { var el = _spacer.prototype.createel.call(this, { classname: this.buildcssclass() }); // no-flex/table-cell mode requires there be some content // in the cell to fill the remaining space of the table. el.innerhtml = ' '; return el; }; return customcontrolspacer; }(_spacer2['default']); _component2['default'].registercomponent('customcontrolspacer', customcontrolspacer); exports['default'] = customcontrolspacer; },{"22":22,"5":5}],22:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file spacer.js */ /** * just an empty spacer element that can be used as an append point for plugins, etc. * also can be used to create space between elements when necessary. * * @extends component */ var spacer = function (_component) { _inherits(spacer, _component); function spacer() { _classcallcheck(this, spacer); return _possibleconstructorreturn(this, _component.apply(this, arguments)); } /** * builds the default dom `classname`. * * @return {string} * the dom `classname` for this object. */ spacer.prototype.buildcssclass = function buildcssclass() { return 'vjs-spacer ' + _component.prototype.buildcssclass.call(this); }; /** * create the `component`'s dom element * * @return {element} * the element that was created. */ spacer.prototype.createel = function createel() { return _component.prototype.createel.call(this, 'div', { classname: this.buildcssclass() }); }; return spacer; }(_component2['default']); _component2['default'].registercomponent('spacer', spacer); exports['default'] = spacer; },{"5":5}],23:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _texttrackmenuitem = _dereq_(31); var _texttrackmenuitem2 = _interoprequiredefault(_texttrackmenuitem); var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file caption-settings-menu-item.js */ /** * the menu item for caption track settings menu * * @extends texttrackmenuitem */ var captionsettingsmenuitem = function (_texttrackmenuitem) { _inherits(captionsettingsmenuitem, _texttrackmenuitem); /** * creates an instance of this class. * * @param {player} player * the `player` that this class should be attached to. * * @param {object} [options] * the key/value store of player options. */ function captionsettingsmenuitem(player, options) { _classcallcheck(this, captionsettingsmenuitem); options.track = { player: player, kind: options.kind, label: options.kind + ' settings', selectable: false, 'default': false, mode: 'disabled' }; // captionsettingsmenuitem has no concept of 'selected' options.selectable = false; var _this = _possibleconstructorreturn(this, _texttrackmenuitem.call(this, player, options)); _this.addclass('vjs-texttrack-settings'); _this.controltext(', opens ' + options.kind + ' settings dialog'); return _this; } /** * this gets called when an `captionsettingsmenuitem` is "clicked". see * {@link clickablecomponent} for more detailed information on what a click can be. * * @param {eventtarget~event} [event] * the `keydown`, `tap`, or `click` event that caused this function to be * called. * * @listens tap * @listens click */ captionsettingsmenuitem.prototype.handleclick = function handleclick(event) { this.player().getchild('texttracksettings').show(); this.player().getchild('texttracksettings').el_.focus(); }; return captionsettingsmenuitem; }(_texttrackmenuitem2['default']); _component2['default'].registercomponent('captionsettingsmenuitem', captionsettingsmenuitem); exports['default'] = captionsettingsmenuitem; },{"31":31,"5":5}],24:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _texttrackbutton = _dereq_(30); var _texttrackbutton2 = _interoprequiredefault(_texttrackbutton); var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); var _captionsettingsmenuitem = _dereq_(23); var _captionsettingsmenuitem2 = _interoprequiredefault(_captionsettingsmenuitem); function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file captions-button.js */ /** * the button component for toggling and selecting captions * * @extends texttrackbutton */ var captionsbutton = function (_texttrackbutton) { _inherits(captionsbutton, _texttrackbutton); /** * creates an instance of this class. * * @param {player} player * the `player` that this class should be attached to. * * @param {object} [options] * the key/value store of player options. * * @param {component~readycallback} [ready] * the function to call when this component is ready. */ function captionsbutton(player, options, ready) { _classcallcheck(this, captionsbutton); var _this = _possibleconstructorreturn(this, _texttrackbutton.call(this, player, options, ready)); _this.el_.setattribute('aria-label', 'captions menu'); return _this; } /** * builds the default dom `classname`. * * @return {string} * the dom `classname` for this object. */ captionsbutton.prototype.buildcssclass = function buildcssclass() { return 'vjs-captions-button ' + _texttrackbutton.prototype.buildcssclass.call(this); }; /** * create caption menu items * * @return {captionsettingsmenuitem[]} * the array of current menu items. */ captionsbutton.prototype.createitems = function createitems() { var items = []; if (!(this.player().tech_ && this.player().tech_.featuresnativetexttracks)) { items.push(new _captionsettingsmenuitem2['default'](this.player_, { kind: this.kind_ })); this.hidethreshold_ += 1; } return _texttrackbutton.prototype.createitems.call(this, items); }; return captionsbutton; }(_texttrackbutton2['default']); /** * `kind` of texttrack to look for to associate it with this menu. * * @type {string} * @private */ captionsbutton.prototype.kind_ = 'captions'; /** * the text that should display over the `captionsbutton`s controls. added for localization. * * @type {string} * @private */ captionsbutton.prototype.controltext_ = 'captions'; _component2['default'].registercomponent('captionsbutton', captionsbutton); exports['default'] = captionsbutton; },{"23":23,"30":30,"5":5}],25:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _texttrackbutton = _dereq_(30); var _texttrackbutton2 = _interoprequiredefault(_texttrackbutton); var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); var _chapterstrackmenuitem = _dereq_(26); var _chapterstrackmenuitem2 = _interoprequiredefault(_chapterstrackmenuitem); var _totitlecase = _dereq_(91); var _totitlecase2 = _interoprequiredefault(_totitlecase); function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file chapters-button.js */ /** * the button component for toggling and selecting chapters * chapters act much differently than other text tracks * cues are navigation vs. other tracks of alternative languages * * @extends texttrackbutton */ var chaptersbutton = function (_texttrackbutton) { _inherits(chaptersbutton, _texttrackbutton); /** * creates an instance of this class. * * @param {player} player * the `player` that this class should be attached to. * * @param {object} [options] * the key/value store of player options. * * @param {component~readycallback} [ready] * the function to call when this function is ready. */ function chaptersbutton(player, options, ready) { _classcallcheck(this, chaptersbutton); var _this = _possibleconstructorreturn(this, _texttrackbutton.call(this, player, options, ready)); _this.el_.setattribute('aria-label', 'chapters menu'); return _this; } /** * builds the default dom `classname`. * * @return {string} * the dom `classname` for this object. */ chaptersbutton.prototype.buildcssclass = function buildcssclass() { return 'vjs-chapters-button ' + _texttrackbutton.prototype.buildcssclass.call(this); }; /** * update the menu based on the current state of its items. * * @param {eventtarget~event} [event] * an event that triggered this function to run. * * @listens texttracklist#addtrack * @listens texttracklist#removetrack * @listens texttracklist#change */ chaptersbutton.prototype.update = function update(event) { if (!this.track_ || event && (event.type === 'addtrack' || event.type === 'removetrack')) { this.settrack(this.findchapterstrack()); } _texttrackbutton.prototype.update.call(this); }; /** * set the currently selected track for the chapters button. * * @param {texttrack} track * the new track to select. nothing will change if this is the currently selected * track. */ chaptersbutton.prototype.settrack = function settrack(track) { if (this.track_ === track) { return; } if (!this.updatehandler_) { this.updatehandler_ = this.update.bind(this); } // here this.track_ refers to the old track instance if (this.track_) { var remotetexttrackel = this.player_.remotetexttrackels().gettrackelementbytrack_(this.track_); if (remotetexttrackel) { remotetexttrackel.removeeventlistener('load', this.updatehandler_); } this.track_ = null; } this.track_ = track; // here this.track_ refers to the new track instance if (this.track_) { this.track_.mode = 'hidden'; var _remotetexttrackel = this.player_.remotetexttrackels().gettrackelementbytrack_(this.track_); if (_remotetexttrackel) { _remotetexttrackel.addeventlistener('load', this.updatehandler_); } } }; /** * find the track object that is currently in use by this chaptersbutton * * @return {texttrack|undefined} * the current track or undefined if none was found. */ chaptersbutton.prototype.findchapterstrack = function findchapterstrack() { var tracks = this.player_.texttracks() || []; for (var i = tracks.length - 1; i >= 0; i--) { // we will always choose the last track as our chapterstrack var track = tracks[i]; if (track.kind === this.kind_) { return track; } } }; /** * get the caption for the chaptersbutton based on the track label. this will also * use the current tracks localized kind as a fallback if a label does not exist. * * @return {string} * the tracks current label or the localized track kind. */ chaptersbutton.prototype.getmenucaption = function getmenucaption() { if (this.track_ && this.track_.label) { return this.track_.label; } return this.localize((0, _totitlecase2['default'])(this.kind_)); }; /** * create menu from chapter track * * @return {menu} * new menu for the chapter buttons */ chaptersbutton.prototype.createmenu = function createmenu() { this.options_.title = this.getmenucaption(); return _texttrackbutton.prototype.createmenu.call(this); }; /** * create a menu item for each text track * * @return {texttrackmenuitem[]} * array of menu items */ chaptersbutton.prototype.createitems = function createitems() { var items = []; if (!this.track_) { return items; } var cues = this.track_.cues; if (!cues) { return items; } for (var i = 0, l = cues.length; i < l; i++) { var cue = cues[i]; var mi = new _chapterstrackmenuitem2['default'](this.player_, { track: this.track_, cue: cue }); items.push(mi); } return items; }; return chaptersbutton; }(_texttrackbutton2['default']); /** * `kind` of texttrack to look for to associate it with this menu. * * @type {string} * @private */ chaptersbutton.prototype.kind_ = 'chapters'; /** * the text that should display over the `chaptersbutton`s controls. added for localization. * * @type {string} * @private */ chaptersbutton.prototype.controltext_ = 'chapters'; _component2['default'].registercomponent('chaptersbutton', chaptersbutton); exports['default'] = chaptersbutton; },{"26":26,"30":30,"5":5,"91":91}],26:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _menuitem = _dereq_(48); var _menuitem2 = _interoprequiredefault(_menuitem); var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); var _fn = _dereq_(83); var fn = _interoprequirewildcard(_fn); function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file chapters-track-menu-item.js */ /** * the chapter track menu item * * @extends menuitem */ var chapterstrackmenuitem = function (_menuitem) { _inherits(chapterstrackmenuitem, _menuitem); /** * creates an instance of this class. * * @param {player} player * the `player` that this class should be attached to. * * @param {object} [options] * the key/value store of player options. */ function chapterstrackmenuitem(player, options) { _classcallcheck(this, chapterstrackmenuitem); var track = options.track; var cue = options.cue; var currenttime = player.currenttime(); // modify options for parent menuitem class's init. options.selectable = true; options.label = cue.text; options.selected = cue.starttime <= currenttime && currenttime < cue.endtime; var _this = _possibleconstructorreturn(this, _menuitem.call(this, player, options)); _this.track = track; _this.cue = cue; track.addeventlistener('cuechange', fn.bind(_this, _this.update)); return _this; } /** * this gets called when an `chapterstrackmenuitem` is "clicked". see * {@link clickablecomponent} for more detailed information on what a click can be. * * @param {eventtarget~event} [event] * the `keydown`, `tap`, or `click` event that caused this function to be * called. * * @listens tap * @listens click */ chapterstrackmenuitem.prototype.handleclick = function handleclick(event) { _menuitem.prototype.handleclick.call(this); this.player_.currenttime(this.cue.starttime); this.update(this.cue.starttime); }; /** * update chapter menu item * * @param {eventtarget~event} [event] * the `cuechange` event that caused this function to run. * * @listens texttrack#cuechange */ chapterstrackmenuitem.prototype.update = function update(event) { var cue = this.cue; var currenttime = this.player_.currenttime(); // vjs.log(currenttime, cue.starttime); this.selected(cue.starttime <= currenttime && currenttime < cue.endtime); }; return chapterstrackmenuitem; }(_menuitem2['default']); _component2['default'].registercomponent('chapterstrackmenuitem', chapterstrackmenuitem); exports['default'] = chapterstrackmenuitem; },{"48":48,"5":5,"83":83}],27:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _texttrackbutton = _dereq_(30); var _texttrackbutton2 = _interoprequiredefault(_texttrackbutton); var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); var _fn = _dereq_(83); var fn = _interoprequirewildcard(_fn); function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file descriptions-button.js */ /** * the button component for toggling and selecting descriptions * * @extends texttrackbutton */ var descriptionsbutton = function (_texttrackbutton) { _inherits(descriptionsbutton, _texttrackbutton); /** * creates an instance of this class. * * @param {player} player * the `player` that this class should be attached to. * * @param {object} [options] * the key/value store of player options. * * @param {component~readycallback} [ready] * the function to call when this component is ready. */ function descriptionsbutton(player, options, ready) { _classcallcheck(this, descriptionsbutton); var _this = _possibleconstructorreturn(this, _texttrackbutton.call(this, player, options, ready)); _this.el_.setattribute('aria-label', 'descriptions menu'); var tracks = player.texttracks(); if (tracks) { var changehandler = fn.bind(_this, _this.handletrackschange); tracks.addeventlistener('change', changehandler); _this.on('dispose', function () { tracks.removeeventlistener('change', changehandler); }); } return _this; } /** * handle text track change * * @param {eventtarget~event} event * the event that caused this function to run * * @listens texttracklist#change */ descriptionsbutton.prototype.handletrackschange = function handletrackschange(event) { var tracks = this.player().texttracks(); var disabled = false; // check whether a track of a different kind is showing for (var i = 0, l = tracks.length; i < l; i++) { var track = tracks[i]; if (track.kind !== this.kind_ && track.mode === 'showing') { disabled = true; break; } } // if another track is showing, disable this menu button if (disabled) { this.disable(); } else { this.enable(); } }; /** * builds the default dom `classname`. * * @return {string} * the dom `classname` for this object. */ descriptionsbutton.prototype.buildcssclass = function buildcssclass() { return 'vjs-descriptions-button ' + _texttrackbutton.prototype.buildcssclass.call(this); }; return descriptionsbutton; }(_texttrackbutton2['default']); /** * `kind` of texttrack to look for to associate it with this menu. * * @type {string} * @private */ descriptionsbutton.prototype.kind_ = 'descriptions'; /** * the text that should display over the `descriptionsbutton`s controls. added for localization. * * @type {string} * @private */ descriptionsbutton.prototype.controltext_ = 'descriptions'; _component2['default'].registercomponent('descriptionsbutton', descriptionsbutton); exports['default'] = descriptionsbutton; },{"30":30,"5":5,"83":83}],28:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _texttrackmenuitem = _dereq_(31); var _texttrackmenuitem2 = _interoprequiredefault(_texttrackmenuitem); var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file off-text-track-menu-item.js */ /** * a special menu item for turning of a specific type of text track * * @extends texttrackmenuitem */ var offtexttrackmenuitem = function (_texttrackmenuitem) { _inherits(offtexttrackmenuitem, _texttrackmenuitem); /** * creates an instance of this class. * * @param {player} player * the `player` that this class should be attached to. * * @param {object} [options] * the key/value store of player options. */ function offtexttrackmenuitem(player, options) { _classcallcheck(this, offtexttrackmenuitem); // create pseudo track info // requires options['kind'] options.track = { player: player, kind: options.kind, label: options.kind + ' off', 'default': false, mode: 'disabled' }; // menuitem is selectable options.selectable = true; var _this = _possibleconstructorreturn(this, _texttrackmenuitem.call(this, player, options)); _this.selected(true); return _this; } /** * handle text track change * * @param {eventtarget~event} event * the event that caused this function to run */ offtexttrackmenuitem.prototype.handletrackschange = function handletrackschange(event) { var tracks = this.player().texttracks(); var selected = true; for (var i = 0, l = tracks.length; i < l; i++) { var track = tracks[i]; if (track.kind === this.track.kind && track.mode === 'showing') { selected = false; break; } } this.selected(selected); }; return offtexttrackmenuitem; }(_texttrackmenuitem2['default']); _component2['default'].registercomponent('offtexttrackmenuitem', offtexttrackmenuitem); exports['default'] = offtexttrackmenuitem; },{"31":31,"5":5}],29:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _texttrackbutton = _dereq_(30); var _texttrackbutton2 = _interoprequiredefault(_texttrackbutton); var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file subtitles-button.js */ /** * the button component for toggling and selecting subtitles * * @extends texttrackbutton */ var subtitlesbutton = function (_texttrackbutton) { _inherits(subtitlesbutton, _texttrackbutton); /** * creates an instance of this class. * * @param {player} player * the `player` that this class should be attached to. * * @param {object} [options] * the key/value store of player options. * * @param {component~readycallback} [ready] * the function to call when this component is ready. */ function subtitlesbutton(player, options, ready) { _classcallcheck(this, subtitlesbutton); var _this = _possibleconstructorreturn(this, _texttrackbutton.call(this, player, options, ready)); _this.el_.setattribute('aria-label', 'subtitles menu'); return _this; } /** * builds the default dom `classname`. * * @return {string} * the dom `classname` for this object. */ subtitlesbutton.prototype.buildcssclass = function buildcssclass() { return 'vjs-subtitles-button ' + _texttrackbutton.prototype.buildcssclass.call(this); }; return subtitlesbutton; }(_texttrackbutton2['default']); /** * `kind` of texttrack to look for to associate it with this menu. * * @type {string} * @private */ subtitlesbutton.prototype.kind_ = 'subtitles'; /** * the text that should display over the `subtitlesbutton`s controls. added for localization. * * @type {string} * @private */ subtitlesbutton.prototype.controltext_ = 'subtitles'; _component2['default'].registercomponent('subtitlesbutton', subtitlesbutton); exports['default'] = subtitlesbutton; },{"30":30,"5":5}],30:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _trackbutton = _dereq_(36); var _trackbutton2 = _interoprequiredefault(_trackbutton); var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); var _texttrackmenuitem = _dereq_(31); var _texttrackmenuitem2 = _interoprequiredefault(_texttrackmenuitem); var _offtexttrackmenuitem = _dereq_(28); var _offtexttrackmenuitem2 = _interoprequiredefault(_offtexttrackmenuitem); function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file text-track-button.js */ /** * the base class for buttons that toggle specific text track types (e.g. subtitles) * * @extends menubutton */ var texttrackbutton = function (_trackbutton) { _inherits(texttrackbutton, _trackbutton); /** * creates an instance of this class. * * @param {player} player * the `player` that this class should be attached to. * * @param {object} [options={}] * the key/value store of player options. */ function texttrackbutton(player) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; _classcallcheck(this, texttrackbutton); options.tracks = player.texttracks(); return _possibleconstructorreturn(this, _trackbutton.call(this, player, options)); } /** * create a menu item for each text track * * @param {texttrackmenuitem[]} [items=[]] * existing array of items to use during creation * * @return {texttrackmenuitem[]} * array of menu items that were created */ texttrackbutton.prototype.createitems = function createitems() { var items = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; // add an off menu item to turn all tracks off items.push(new _offtexttrackmenuitem2['default'](this.player_, { kind: this.kind_ })); this.hidethreshold_ += 1; var tracks = this.player_.texttracks(); if (!tracks) { return items; } for (var i = 0; i < tracks.length; i++) { var track = tracks[i]; // only add tracks that are of the appropriate kind and have a label if (track.kind === this.kind_) { items.push(new _texttrackmenuitem2['default'](this.player_, { track: track, // menuitem is selectable selectable: true })); } } return items; }; return texttrackbutton; }(_trackbutton2['default']); _component2['default'].registercomponent('texttrackbutton', texttrackbutton); exports['default'] = texttrackbutton; },{"28":28,"31":31,"36":36,"5":5}],31:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _typeof = typeof symbol === "function" && typeof symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof symbol === "function" && obj.constructor === symbol && obj !== symbol.prototype ? "symbol" : typeof obj; }; var _menuitem = _dereq_(48); var _menuitem2 = _interoprequiredefault(_menuitem); var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); var _fn = _dereq_(83); var fn = _interoprequirewildcard(_fn); var _window = _dereq_(95); var _window2 = _interoprequiredefault(_window); var _document = _dereq_(94); var _document2 = _interoprequiredefault(_document); function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file text-track-menu-item.js */ /** * the specific menu item type for selecting a language within a text track kind * * @extends menuitem */ var texttrackmenuitem = function (_menuitem) { _inherits(texttrackmenuitem, _menuitem); /** * creates an instance of this class. * * @param {player} player * the `player` that this class should be attached to. * * @param {object} [options] * the key/value store of player options. */ function texttrackmenuitem(player, options) { _classcallcheck(this, texttrackmenuitem); var track = options.track; var tracks = player.texttracks(); // modify options for parent menuitem class's init. options.label = track.label || track.language || 'unknown'; options.selected = track['default'] || track.mode === 'showing'; var _this = _possibleconstructorreturn(this, _menuitem.call(this, player, options)); _this.track = track; if (tracks) { var changehandler = fn.bind(_this, _this.handletrackschange); player.on(['loadstart', 'texttrackchange'], changehandler); tracks.addeventlistener('change', changehandler); _this.on('dispose', function () { tracks.removeeventlistener('change', changehandler); }); } // ios7 doesn't dispatch change events to texttracklists when an // associated track's mode changes. without something like // object.observe() (also not present on ios7), it's not // possible to detect changes to the mode attribute and polyfill // the change event. as a poor substitute, we manually dispatch // change events whenever the controls modify the mode. if (tracks && tracks.onchange === undefined) { var event = void 0; _this.on(['tap', 'click'], function () { if (_typeof(_window2['default'].event) !== 'object') { // android 2.3 throws an illegal constructor error for window.event try { event = new _window2['default'].event('change'); } catch (err) { // continue regardless of error } } if (!event) { event = _document2['default'].createevent('event'); event.initevent('change', true, true); } tracks.dispatchevent(event); }); } return _this; } /** * this gets called when an `texttrackmenuitem` is "clicked". see * {@link clickablecomponent} for more detailed information on what a click can be. * * @param {eventtarget~event} event * the `keydown`, `tap`, or `click` event that caused this function to be * called. * * @listens tap * @listens click */ texttrackmenuitem.prototype.handleclick = function handleclick(event) { var kind = this.track.kind; var tracks = this.player_.texttracks(); _menuitem.prototype.handleclick.call(this, event); if (!tracks) { return; } for (var i = 0; i < tracks.length; i++) { var track = tracks[i]; if (track.kind !== kind) { continue; } if (track === this.track) { track.mode = 'showing'; } else { track.mode = 'disabled'; } } }; /** * handle text track list change * * @param {eventtarget~event} event * the `change` event that caused this function to be called. * * @listens texttracklist#change */ texttrackmenuitem.prototype.handletrackschange = function handletrackschange(event) { this.selected(this.track.mode === 'showing'); }; return texttrackmenuitem; }(_menuitem2['default']); _component2['default'].registercomponent('texttrackmenuitem', texttrackmenuitem); exports['default'] = texttrackmenuitem; },{"48":48,"5":5,"83":83,"94":94,"95":95}],32:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); var _dom = _dereq_(81); var dom = _interoprequirewildcard(_dom); var _formattime = _dereq_(84); var _formattime2 = _interoprequiredefault(_formattime); function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file current-time-display.js */ /** * displays the current time * * @extends component */ var currenttimedisplay = function (_component) { _inherits(currenttimedisplay, _component); /** * creates an instance of this class. * * @param {player} player * the `player` that this class should be attached to. * * @param {object} [options] * the key/value store of player options. */ function currenttimedisplay(player, options) { _classcallcheck(this, currenttimedisplay); var _this = _possibleconstructorreturn(this, _component.call(this, player, options)); _this.on(player, 'timeupdate', _this.updatecontent); return _this; } /** * create the `component`'s dom element * * @return {element} * the element that was created. */ currenttimedisplay.prototype.createel = function createel() { var el = _component.prototype.createel.call(this, 'div', { classname: 'vjs-current-time vjs-time-control vjs-control' }); this.contentel_ = dom.createel('div', { classname: 'vjs-current-time-display', // label the current time for screen reader users innerhtml: 'current time ' + '0:00' }, { // tell screen readers not to automatically read the time as it changes 'aria-live': 'off' }); el.appendchild(this.contentel_); return el; }; /** * update current time display * * @param {eventtarget~event} [event] * the `timeupdate` event that caused this function to run. * * @listens player#timeupdate */ currenttimedisplay.prototype.updatecontent = function updatecontent(event) { // allows for smooth scrubbing, when player can't keep up. var time = this.player_.scrubbing() ? this.player_.getcache().currenttime : this.player_.currenttime(); var localizedtext = this.localize('current time'); var formattedtime = (0, _formattime2['default'])(time, this.player_.duration()); if (formattedtime !== this.formattedtime_) { this.formattedtime_ = formattedtime; this.contentel_.innerhtml = '' + localizedtext + ' ' + formattedtime; } }; return currenttimedisplay; }(_component2['default']); _component2['default'].registercomponent('currenttimedisplay', currenttimedisplay); exports['default'] = currenttimedisplay; },{"5":5,"81":81,"84":84}],33:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); var _dom = _dereq_(81); var dom = _interoprequirewildcard(_dom); var _formattime = _dereq_(84); var _formattime2 = _interoprequiredefault(_formattime); function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file duration-display.js */ /** * displays the duration * * @extends component */ var durationdisplay = function (_component) { _inherits(durationdisplay, _component); /** * creates an instance of this class. * * @param {player} player * the `player` that this class should be attached to. * * @param {object} [options] * the key/value store of player options. */ function durationdisplay(player, options) { _classcallcheck(this, durationdisplay); var _this = _possibleconstructorreturn(this, _component.call(this, player, options)); _this.on(player, 'durationchange', _this.updatecontent); // also listen for timeupdate and loadedmetadata because removing those // listeners could have broken dependent applications/libraries. these // can likely be removed for 6.0. _this.on(player, 'timeupdate', _this.updatecontent); _this.on(player, 'loadedmetadata', _this.updatecontent); return _this; } /** * create the `component`'s dom element * * @return {element} * the element that was created. */ durationdisplay.prototype.createel = function createel() { var el = _component.prototype.createel.call(this, 'div', { classname: 'vjs-duration vjs-time-control vjs-control' }); this.contentel_ = dom.createel('div', { classname: 'vjs-duration-display', // label the duration time for screen reader users innerhtml: '' + this.localize('duration time') + ' 0:00' }, { // tell screen readers not to automatically read the time as it changes 'aria-live': 'off' }); el.appendchild(this.contentel_); return el; }; /** * update duration time display. * * @param {eventtarget~event} [event] * the `durationchange`, `timeupdate`, or `loadedmetadata` event that caused * this function to be called. * * @listens player#durationchange * @listens player#timeupdate * @listens player#loadedmetadata */ durationdisplay.prototype.updatecontent = function updatecontent(event) { var duration = this.player_.duration(); if (duration && this.duration_ !== duration) { this.duration_ = duration; var localizedtext = this.localize('duration time'); var formattedtime = (0, _formattime2['default'])(duration); // label the duration time for screen reader users this.contentel_.innerhtml = '' + localizedtext + ' ' + formattedtime; } }; return durationdisplay; }(_component2['default']); _component2['default'].registercomponent('durationdisplay', durationdisplay); exports['default'] = durationdisplay; },{"5":5,"81":81,"84":84}],34:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); var _dom = _dereq_(81); var dom = _interoprequirewildcard(_dom); var _formattime = _dereq_(84); var _formattime2 = _interoprequiredefault(_formattime); function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file remaining-time-display.js */ /** * displays the time left in the video * * @extends component */ var remainingtimedisplay = function (_component) { _inherits(remainingtimedisplay, _component); /** * creates an instance of this class. * * @param {player} player * the `player` that this class should be attached to. * * @param {object} [options] * the key/value store of player options. */ function remainingtimedisplay(player, options) { _classcallcheck(this, remainingtimedisplay); var _this = _possibleconstructorreturn(this, _component.call(this, player, options)); _this.on(player, 'timeupdate', _this.updatecontent); _this.on(player, 'durationchange', _this.updatecontent); return _this; } /** * create the `component`'s dom element * * @return {element} * the element that was created. */ remainingtimedisplay.prototype.createel = function createel() { var el = _component.prototype.createel.call(this, 'div', { classname: 'vjs-remaining-time vjs-time-control vjs-control' }); this.contentel_ = dom.createel('div', { classname: 'vjs-remaining-time-display', // label the remaining time for screen reader users innerhtml: '' + this.localize('remaining time') + ' -0:00' }, { // tell screen readers not to automatically read the time as it changes 'aria-live': 'off' }); el.appendchild(this.contentel_); return el; }; /** * update remaining time display. * * @param {eventtarget~event} [event] * the `timeupdate` or `durationchange` event that caused this to run. * * @listens player#timeupdate * @listens player#durationchange */ remainingtimedisplay.prototype.updatecontent = function updatecontent(event) { if (this.player_.duration()) { var localizedtext = this.localize('remaining time'); var formattedtime = (0, _formattime2['default'])(this.player_.remainingtime()); if (formattedtime !== this.formattedtime_) { this.formattedtime_ = formattedtime; this.contentel_.innerhtml = '' + localizedtext + ' -' + formattedtime; } } // allows for smooth scrubbing, when player can't keep up. // var time = (this.player_.scrubbing()) ? this.player_.getcache().currenttime : this.player_.currenttime(); // this.contentel_.innerhtml = vjs.formattime(time, this.player_.duration()); }; return remainingtimedisplay; }(_component2['default']); _component2['default'].registercomponent('remainingtimedisplay', remainingtimedisplay); exports['default'] = remainingtimedisplay; },{"5":5,"81":81,"84":84}],35:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file time-divider.js */ /** * the separator between the current time and duration. * can be hidden if it's not needed in the design. * * @extends component */ var timedivider = function (_component) { _inherits(timedivider, _component); function timedivider() { _classcallcheck(this, timedivider); return _possibleconstructorreturn(this, _component.apply(this, arguments)); } /** * create the component's dom element * * @return {element} * the element that was created. */ timedivider.prototype.createel = function createel() { return _component.prototype.createel.call(this, 'div', { classname: 'vjs-time-control vjs-time-divider', innerhtml: '
/
' }); }; return timedivider; }(_component2['default']); _component2['default'].registercomponent('timedivider', timedivider); exports['default'] = timedivider; },{"5":5}],36:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _menubutton = _dereq_(47); var _menubutton2 = _interoprequiredefault(_menubutton); var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); var _fn = _dereq_(83); var fn = _interoprequirewildcard(_fn); function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file track-button.js */ /** * the base class for buttons that toggle specific track types (e.g. subtitles). * * @extends menubutton */ var trackbutton = function (_menubutton) { _inherits(trackbutton, _menubutton); /** * creates an instance of this class. * * @param {player} player * the `player` that this class should be attached to. * * @param {object} [options] * the key/value store of player options. */ function trackbutton(player, options) { _classcallcheck(this, trackbutton); var tracks = options.tracks; var _this = _possibleconstructorreturn(this, _menubutton.call(this, player, options)); if (_this.items.length <= 1) { _this.hide(); } if (!tracks) { return _possibleconstructorreturn(_this); } var updatehandler = fn.bind(_this, _this.update); tracks.addeventlistener('removetrack', updatehandler); tracks.addeventlistener('addtrack', updatehandler); _this.player_.on('dispose', function () { tracks.removeeventlistener('removetrack', updatehandler); tracks.removeeventlistener('addtrack', updatehandler); }); return _this; } return trackbutton; }(_menubutton2['default']); _component2['default'].registercomponent('trackbutton', trackbutton); exports['default'] = trackbutton; },{"47":47,"5":5,"83":83}],37:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _slider = _dereq_(57); var _slider2 = _interoprequiredefault(_slider); var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); var _fn = _dereq_(83); var fn = _interoprequirewildcard(_fn); _dereq_(39); function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file volume-bar.js */ // required children /** * the bar that contains the volume level and can be clicked on to adjust the level * * @extends slider */ var volumebar = function (_slider) { _inherits(volumebar, _slider); /** * creates an instance of this class. * * @param {player} player * the `player` that this class should be attached to. * * @param {object} [options] * the key/value store of player options. */ function volumebar(player, options) { _classcallcheck(this, volumebar); var _this = _possibleconstructorreturn(this, _slider.call(this, player, options)); _this.on(player, 'volumechange', _this.updateariaattributes); player.ready(fn.bind(_this, _this.updateariaattributes)); return _this; } /** * create the `component`'s dom element * * @return {element} * the element that was created. */ volumebar.prototype.createel = function createel() { return _slider.prototype.createel.call(this, 'div', { classname: 'vjs-volume-bar vjs-slider-bar' }, { 'aria-label': 'volume level' }); }; /** * handle movement events on the {@link volumemenubutton}. * * @param {eventtarget~event} event * the event that caused this function to run. * * @listens mousemove */ volumebar.prototype.handlemousemove = function handlemousemove(event) { this.checkmuted(); this.player_.volume(this.calculatedistance(event)); }; /** * if the player is muted unmute it. */ volumebar.prototype.checkmuted = function checkmuted() { if (this.player_.muted()) { this.player_.muted(false); } }; /** * get percent of volume level * * @return {number} * volume level percent as a decimal number. */ volumebar.prototype.getpercent = function getpercent() { if (this.player_.muted()) { return 0; } return this.player_.volume(); }; /** * increase volume level for keyboard users */ volumebar.prototype.stepforward = function stepforward() { this.checkmuted(); this.player_.volume(this.player_.volume() + 0.1); }; /** * decrease volume level for keyboard users */ volumebar.prototype.stepback = function stepback() { this.checkmuted(); this.player_.volume(this.player_.volume() - 0.1); }; /** * update aria accessibility attributes * * @param {eventtarget~event} [event] * the `volumechange` event that caused this function to run. * * @listens player#volumechange */ volumebar.prototype.updateariaattributes = function updateariaattributes(event) { // current value of volume bar as a percentage var volume = (this.player_.volume() * 100).tofixed(2); this.el_.setattribute('aria-valuenow', volume); this.el_.setattribute('aria-valuetext', volume + '%'); }; return volumebar; }(_slider2['default']); /** * default options for the `volumebar` * * @type {object} * @private */ volumebar.prototype.options_ = { children: ['volumelevel'], barname: 'volumelevel' }; /** * call the update event for this slider when this event happens on the player. * * @type {string} */ volumebar.prototype.playerevent = 'volumechange'; _component2['default'].registercomponent('volumebar', volumebar); exports['default'] = volumebar; },{"39":39,"5":5,"57":57,"83":83}],38:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); _dereq_(37); function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file volume-control.js */ // required children /** * the component for controlling the volume level * * @extends component */ var volumecontrol = function (_component) { _inherits(volumecontrol, _component); /** * creates an instance of this class. * * @param {player} player * the `player` that this class should be attached to. * * @param {object} [options={}] * the key/value store of player options. */ function volumecontrol(player, options) { _classcallcheck(this, volumecontrol); // hide volume controls when they're not supported by the current tech var _this = _possibleconstructorreturn(this, _component.call(this, player, options)); if (player.tech_ && player.tech_.featuresvolumecontrol === false) { _this.addclass('vjs-hidden'); } _this.on(player, 'loadstart', function () { if (player.tech_.featuresvolumecontrol === false) { this.addclass('vjs-hidden'); } else { this.removeclass('vjs-hidden'); } }); return _this; } /** * create the `component`'s dom element * * @return {element} * the element that was created. */ volumecontrol.prototype.createel = function createel() { return _component.prototype.createel.call(this, 'div', { classname: 'vjs-volume-control vjs-control' }); }; return volumecontrol; }(_component2['default']); /** * default options for the `volumecontrol` * * @type {object} * @private */ volumecontrol.prototype.options_ = { children: ['volumebar'] }; _component2['default'].registercomponent('volumecontrol', volumecontrol); exports['default'] = volumecontrol; },{"37":37,"5":5}],39:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file volume-level.js */ /** * shows volume level * * @extends component */ var volumelevel = function (_component) { _inherits(volumelevel, _component); function volumelevel() { _classcallcheck(this, volumelevel); return _possibleconstructorreturn(this, _component.apply(this, arguments)); } /** * create the `component`'s dom element * * @return {element} * the element that was created. */ volumelevel.prototype.createel = function createel() { return _component.prototype.createel.call(this, 'div', { classname: 'vjs-volume-level', innerhtml: '' }); }; return volumelevel; }(_component2['default']); _component2['default'].registercomponent('volumelevel', volumelevel); exports['default'] = volumelevel; },{"5":5}],40:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _fn = _dereq_(83); var fn = _interoprequirewildcard(_fn); var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); var _popup = _dereq_(54); var _popup2 = _interoprequiredefault(_popup); var _popupbutton = _dereq_(53); var _popupbutton2 = _interoprequiredefault(_popupbutton); var _mutetoggle = _dereq_(11); var _mutetoggle2 = _interoprequiredefault(_mutetoggle); var _volumebar = _dereq_(37); var _volumebar2 = _interoprequiredefault(_volumebar); function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file volume-menu-button.js */ /** * button for volume popup * * @extends popupbutton */ var volumemenubutton = function (_popupbutton) { _inherits(volumemenubutton, _popupbutton); /** * creates an instance of this class. * * @param {player} player * the `player` that this class should be attached to. * * @param {object} [options={}] * the key/value store of player options. */ function volumemenubutton(player) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; _classcallcheck(this, volumemenubutton); // default to inline if (options.inline === undefined) { options.inline = true; } // if the vertical option isn't passed at all, default to true. if (options.vertical === undefined) { // if an inline volumemenubutton is used, we should default to using // a horizontal slider for obvious reasons. if (options.inline) { options.vertical = false; } else { options.vertical = true; } } // the vertical option needs to be set on the volumebar as well, // since that will need to be passed along to the volumebar constructor options.volumebar = options.volumebar || {}; options.volumebar.vertical = !!options.vertical; // same listeners as mutetoggle var _this = _possibleconstructorreturn(this, _popupbutton.call(this, player, options)); _this.on(player, 'volumechange', _this.volumeupdate); _this.on(player, 'loadstart', _this.volumeupdate); // hide mute toggle if the current tech doesn't support volume control function updatevisibility() { if (player.tech_ && player.tech_.featuresvolumecontrol === false) { this.addclass('vjs-hidden'); } else { this.removeclass('vjs-hidden'); } } updatevisibility.call(_this); _this.on(player, 'loadstart', updatevisibility); _this.on(_this.volumebar, ['slideractive', 'focus'], function () { this.addclass('vjs-slider-active'); }); _this.on(_this.volumebar, ['sliderinactive', 'blur'], function () { this.removeclass('vjs-slider-active'); }); _this.on(_this.volumebar, ['focus'], function () { this.addclass('vjs-lock-showing'); }); _this.on(_this.volumebar, ['blur'], function () { this.removeclass('vjs-lock-showing'); }); return _this; } /** * builds the default dom `classname`. * * @return {string} * the dom `classname` for this object. */ volumemenubutton.prototype.buildcssclass = function buildcssclass() { var orientationclass = ''; if (this.options_.vertical) { orientationclass = 'vjs-volume-menu-button-vertical'; } else { orientationclass = 'vjs-volume-menu-button-horizontal'; } return 'vjs-volume-menu-button ' + _popupbutton.prototype.buildcssclass.call(this) + ' ' + orientationclass; }; /** * create the volumemenubutton popup * * @return {popup} * the popup that was created */ volumemenubutton.prototype.createpopup = function createpopup() { var popup = new _popup2['default'](this.player_, { contenteltype: 'div' }); var vb = new _volumebar2['default'](this.player_, this.options_.volumebar); popup.addchild(vb); this.menucontent = popup; this.volumebar = vb; this.attachvolumebarevents(); return popup; }; /** * this gets called when an `volumemenubutton` is "clicked". see * {@link clickablecomponent} for more detailed information on what a click can be. * * @param {eventtarget~event} [event] * the `keydown`, `tap`, or `click` event that caused this function to be * called. * * @listens tap * @listens click */ volumemenubutton.prototype.handleclick = function handleclick(event) { _mutetoggle2['default'].prototype.handleclick.call(this); _popupbutton.prototype.handleclick.call(this); }; /** * add events listeners to the created `volumebar`. */ volumemenubutton.prototype.attachvolumebarevents = function attachvolumebarevents() { this.menucontent.on(['mousedown', 'touchdown'], fn.bind(this, this.handlemousedown)); }; /** * handle the `mousedown` and `touchdown` events on the `volumebar` * * @param {eventtarget~event} [event] * the `mousedown` or `touchdown` event that caused this to run. * * @listens mousedown * @listens touchdown */ volumemenubutton.prototype.handlemousedown = function handlemousedown(event) { this.on(['mousemove', 'touchmove'], fn.bind(this.volumebar, this.volumebar.handlemousemove)); this.on(this.el_.ownerdocument, ['mouseup', 'touchend'], this.handlemouseup); }; /** * handle the `mouseup` and `touchend` events on the `volumebar` * * @param {eventtarget~event} [event] * the `mouseup` or `touchend` event that caused this to run. * * @listens mouseup * @listens touchend */ volumemenubutton.prototype.handlemouseup = function handlemouseup(event) { this.off(['mousemove', 'touchmove'], fn.bind(this.volumebar, this.volumebar.handlemousemove)); }; return volumemenubutton; }(_popupbutton2['default']); /** * @borrows mutetoggle#update as volumemenubutton#volumeupdate */ volumemenubutton.prototype.volumeupdate = _mutetoggle2['default'].prototype.update; /** * the text that should display over the `volumemenubutton`s controls. added for localization. * * @type {string} * @private */ volumemenubutton.prototype.controltext_ = 'mute'; _component2['default'].registercomponent('volumemenubutton', volumemenubutton); exports['default'] = volumemenubutton; },{"11":11,"37":37,"5":5,"53":53,"54":54,"83":83}],41:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); var _modaldialog = _dereq_(50); var _modaldialog2 = _interoprequiredefault(_modaldialog); var _mergeoptions = _dereq_(87); var _mergeoptions2 = _interoprequiredefault(_mergeoptions); function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file error-display.js */ /** * a display that indicates an error has occurred. this means that the video * is unplayable. * * @extends modaldialog */ var errordisplay = function (_modaldialog) { _inherits(errordisplay, _modaldialog); /** * creates an instance of this class. * * @param {player} player * the `player` that this class should be attached to. * * @param {object} [options] * the key/value store of player options. */ function errordisplay(player, options) { _classcallcheck(this, errordisplay); var _this = _possibleconstructorreturn(this, _modaldialog.call(this, player, options)); _this.on(player, 'error', _this.open); return _this; } /** * builds the default dom `classname`. * * @return {string} * the dom `classname` for this object. * * @deprecated since version 5. */ errordisplay.prototype.buildcssclass = function buildcssclass() { return 'vjs-error-display ' + _modaldialog.prototype.buildcssclass.call(this); }; /** * gets the localized error message based on the `player`s error. * * @return {string} * the `player`s error message localized or an empty string. */ errordisplay.prototype.content = function content() { var error = this.player().error(); return error ? this.localize(error.message) : ''; }; return errordisplay; }(_modaldialog2['default']); /** * the default options for an `errordisplay`. * * @private */ errordisplay.prototype.options_ = (0, _mergeoptions2['default'])(_modaldialog2['default'].prototype.options_, { pauseonopen: false, fillalways: true, temporary: false, uncloseable: true }); _component2['default'].registercomponent('errordisplay', errordisplay); exports['default'] = errordisplay; },{"5":5,"50":50,"87":87}],42:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _events = _dereq_(82); var events = _interoprequirewildcard(_events); function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } /** * `eventtarget` is a class that can have the same api as the dom `eventtarget`. it * adds shorthand functions that wrap around lengthy functions. for example: * the `on` function is a wrapper around `addeventlistener`. * * @see [eventtarget spec]{@link https://www.w3.org/tr/dom-level-2-events/events.html#events-eventtarget} * @class eventtarget */ var eventtarget = function eventtarget() {}; /** * a custom dom event. * * @typedef {object} eventtarget~event * @see [properties]{@link https://developer.mozilla.org/en-us/docs/web/api/customevent} */ /** * all event listeners should follow the following format. * * @callback eventtarget~eventlistener * @this {eventtarget} * * @param {eventtarget~event} event * the event that triggered this function * * @param {object} [hash] * hash of data sent during the event */ /** * an object containing event names as keys and booleans as values. * * > note: if an event name is set to a true value here {@link eventtarget#trigger} * will have extra functionality. see that function for more information. * * @property eventtarget.prototype.allowedevents_ * @private */ /** * @file src/js/event-target.js */ eventtarget.prototype.allowedevents_ = {}; /** * adds an `event listener` to an instance of an `eventtarget`. an `event listener` is a * function that will get called when an event with a certain name gets triggered. * * @param {string|string[]} type * an event name or an array of event names. * * @param {eventtarget~eventlistener} fn * the function to call with `eventtarget`s */ eventtarget.prototype.on = function (type, fn) { // remove the addeventlistener alias before calling events.on // so we don't get into an infinite type loop var ael = this.addeventlistener; this.addeventlistener = function () {}; events.on(this, type, fn); this.addeventlistener = ael; }; /** * an alias of {@link eventtarget#on}. allows `eventtarget` to mimic * the standard dom api. * * @function * @see {@link eventtarget#on} */ eventtarget.prototype.addeventlistener = eventtarget.prototype.on; /** * removes an `event listener` for a specific event from an instance of `eventtarget`. * this makes it so that the `event listener` will no longer get called when the * named event happens. * * @param {string|string[]} type * an event name or an array of event names. * * @param {eventtarget~eventlistener} fn * the function to remove. */ eventtarget.prototype.off = function (type, fn) { events.off(this, type, fn); }; /** * an alias of {@link eventtarget#off}. allows `eventtarget` to mimic * the standard dom api. * * @function * @see {@link eventtarget#off} */ eventtarget.prototype.removeeventlistener = eventtarget.prototype.off; /** * this function will add an `event listener` that gets triggered only once. after the * first trigger it will get removed. this is like adding an `event listener` * with {@link eventtarget#on} that calls {@link eventtarget#off} on itself. * * @param {string|string[]} type * an event name or an array of event names. * * @param {eventtarget~eventlistener} fn * the function to be called once for each event name. */ eventtarget.prototype.one = function (type, fn) { // remove the addeventlistener alialing events.on // so we don't get into an infinite type loop var ael = this.addeventlistener; this.addeventlistener = function () {}; events.one(this, type, fn); this.addeventlistener = ael; }; /** * this function causes an event to happen. this will then cause any `event listeners` * that are waiting for that event, to get called. if there are no `event listeners` * for an event then nothing will happen. * * if the name of the `event` that is being triggered is in `eventtarget.allowedevents_`. * trigger will also call the `on` + `uppercaseeventname` function. * * example: * 'click' is in `eventtarget.allowedevents_`, so, trigger will attempt to call * `onclick` if it exists. * * @param {string|eventtarget~event|object} event * the name of the event, an `event`, or an object with a key of type set to * an event name. */ eventtarget.prototype.trigger = function (event) { var type = event.type || event; if (typeof event === 'string') { event = { type: type }; } event = events.fixevent(event); if (this.allowedevents_[type] && this['on' + type]) { this['on' + type](event); } events.trigger(this, event); }; /** * an alias of {@link eventtarget#trigger}. allows `eventtarget` to mimic * the standard dom api. * * @function * @see {@link eventtarget#trigger} */ eventtarget.prototype.dispatchevent = eventtarget.prototype.trigger; exports['default'] = eventtarget; },{"82":82}],43:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _typeof = typeof symbol === "function" && typeof symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof symbol === "function" && obj.constructor === symbol && obj !== symbol.prototype ? "symbol" : typeof obj; }; var _log = _dereq_(86); var _log2 = _interoprequiredefault(_log); var _obj = _dereq_(88); function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } /** * @file extend.js * @module extend */ /** * a combination of node inherits and babel's inherits (after transpile). * both work the same but node adds `super_` to the subclass * and bable adds the superclass as __proto__. both seem useful. * * @param {object} subclass * the class to inherit to * * @param {object} superclass * the class to inherit from * * @private */ var _inherits = function _inherits(subclass, superclass) { if (typeof superclass !== 'function' && superclass !== null) { throw new typeerror('super expression must either be null or a function, not ' + (typeof superclass === 'undefined' ? 'undefined' : _typeof(superclass))); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) { // node subclass.super_ = superclass; } }; /** * function for subclassing using the same inheritance that * videojs uses internally * * @param {object} superclass * the class to inherit from * * @param {object} [subclassmethods={}] * the class to inherit to * * @return {object} * the new object with subclassmethods that inherited superclass. */ var extendfn = function extendfn(superclass) { var subclassmethods = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var subclass = function subclass() { superclass.apply(this, arguments); }; var methods = {}; if ((0, _obj.isobject)(subclassmethods)) { if (typeof subclassmethods.init === 'function') { _log2['default'].warn('constructor logic via init() is deprecated; please use constructor() instead.'); subclassmethods.constructor = subclassmethods.init; } if (subclassmethods.constructor !== object.prototype.constructor) { subclass = subclassmethods.constructor; } methods = subclassmethods; } else if (typeof subclassmethods === 'function') { subclass = subclassmethods; } _inherits(subclass, superclass); // extend subobj's prototype with functions and other properties from props for (var name in methods) { if (methods.hasownproperty(name)) { subclass.prototype[name] = methods[name]; } } return subclass; }; exports['default'] = extendfn; },{"86":86,"88":88}],44:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _document = _dereq_(94); var _document2 = _interoprequiredefault(_document); function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } /** * store the browser-specific methods for the fullscreen api. * * @type {object} * @see [specification]{@link https://fullscreen.spec.whatwg.org} * @see [map approach from screenfull.js]{@link https://github.com/sindresorhus/screenfull.js} */ var fullscreenapi = {}; // browser api methods /** * @file fullscreen-api.js * @module fullscreen-api * @private */ var apimap = [['requestfullscreen', 'exitfullscreen', 'fullscreenelement', 'fullscreenenabled', 'fullscreenchange', 'fullscreenerror'], // webkit ['webkitrequestfullscreen', 'webkitexitfullscreen', 'webkitfullscreenelement', 'webkitfullscreenenabled', 'webkitfullscreenchange', 'webkitfullscreenerror'], // old webkit (safari 5.1) ['webkitrequestfullscreen', 'webkitcancelfullscreen', 'webkitcurrentfullscreenelement', 'webkitcancelfullscreen', 'webkitfullscreenchange', 'webkitfullscreenerror'], // mozilla ['mozrequestfullscreen', 'mozcancelfullscreen', 'mozfullscreenelement', 'mozfullscreenenabled', 'mozfullscreenchange', 'mozfullscreenerror'], // microsoft ['msrequestfullscreen', 'msexitfullscreen', 'msfullscreenelement', 'msfullscreenenabled', 'msfullscreenchange', 'msfullscreenerror']]; var specapi = apimap[0]; var browserapi = void 0; // determine the supported set of functions for (var i = 0; i < apimap.length; i++) { // check for exitfullscreen function if (apimap[i][1] in _document2['default']) { browserapi = apimap[i]; break; } } // map the browser api names to the spec api names if (browserapi) { for (var _i = 0; _i < browserapi.length; _i++) { fullscreenapi[specapi[_i]] = browserapi[_i]; } } exports['default'] = fullscreenapi; },{"94":94}],45:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file loading-spinner.js */ /** * a loading spinner for use during waiting/loading events. * * @extends component */ var loadingspinner = function (_component) { _inherits(loadingspinner, _component); function loadingspinner() { _classcallcheck(this, loadingspinner); return _possibleconstructorreturn(this, _component.apply(this, arguments)); } /** * create the `loadingspinner`s dom element. * * @return {element} * the dom element that gets created. */ loadingspinner.prototype.createel = function createel() { return _component.prototype.createel.call(this, 'div', { classname: 'vjs-loading-spinner', dir: 'ltr' }); }; return loadingspinner; }(_component2['default']); _component2['default'].registercomponent('loadingspinner', loadingspinner); exports['default'] = loadingspinner; },{"5":5}],46:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _obj = _dereq_(88); /** * a custom `mediaerror` class which mimics the standard html5 `mediaerror` class. * * @param {number|string|object|mediaerror} value * this can be of multiple types: * - number: should be a standard error code * - string: an error message (the code will be 0) * - object: arbitrary properties * - `mediaerror` (native): used to populate a video.js `mediaerror` object * - `mediaerror` (video.js): will return itself if it's already a * video.js `mediaerror` object. * * @see [mediaerror spec]{@link https://dev.w3.org/html5/spec-author-view/video.html#mediaerror} * @see [encrypted mediaerror spec]{@link https://www.w3.org/tr/2013/wd-encrypted-media-20130510/#error-codes} * * @class mediaerror */ function mediaerror(value) { // allow redundant calls to this constructor to avoid having `instanceof` // checks peppered around the code. if (value instanceof mediaerror) { return value; } if (typeof value === 'number') { this.code = value; } else if (typeof value === 'string') { // default code is zero, so this is a custom error this.message = value; } else if ((0, _obj.isobject)(value)) { // we assign the `code` property manually because native `mediaerror` objects // do not expose it as an own/enumerable property of the object. if (typeof value.code === 'number') { this.code = value.code; } (0, _obj.assign)(this, value); } if (!this.message) { this.message = mediaerror.defaultmessages[this.code] || ''; } } /** * the error code that refers two one of the defined `mediaerror` types * * @type {number} */ /** * @file media-error.js */ mediaerror.prototype.code = 0; /** * an optional message that to show with the error. message is not part of the html5 * video spec but allows for more informative custom errors. * * @type {string} */ mediaerror.prototype.message = ''; /** * an optional status code that can be set by plugins to allow even more detail about * the error. for example a plugin might provide a specific http status code and an * error message for that code. then when the plugin gets that error this class will * know how to display an error message for it. this allows a custom message to show * up on the `player` error overlay. * * @type {array} */ mediaerror.prototype.status = null; /** * errors indexed by the w3c standard. the order **cannot change**! see the * specification listed under {@link mediaerror} for more information. * * @enum {array} * @readonly * @property {string} 0 - media_err_custom * @property {string} 1 - media_err_custom * @property {string} 2 - media_err_aborted * @property {string} 3 - media_err_network * @property {string} 4 - media_err_src_not_supported * @property {string} 5 - media_err_encrypted */ mediaerror.errortypes = ['media_err_custom', 'media_err_aborted', 'media_err_network', 'media_err_decode', 'media_err_src_not_supported', 'media_err_encrypted']; /** * the default `mediaerror` messages based on the {@link mediaerror.errortypes}. * * @type {array} * @constant */ mediaerror.defaultmessages = { 1: 'you aborted the media playback', 2: 'a network error caused the media download to fail part-way.', 3: 'the media playback was aborted due to a corruption problem or because the media used features your browser did not support.', 4: 'the media could not be loaded, either because the server or network failed or because the format is not supported.', 5: 'the media is encrypted and we do not have the keys to decrypt it.' }; // add types as properties on mediaerror // e.g. mediaerror.media_err_src_not_supported = 4; for (var errnum = 0; errnum < mediaerror.errortypes.length; errnum++) { mediaerror[mediaerror.errortypes[errnum]] = errnum; // values should be accessible on both the class and instance mediaerror.prototype[mediaerror.errortypes[errnum]] = errnum; } // jsdocs for instance/static members added above // instance methods use `#` and static methods use `.` /** * w3c error code for any custom error. * * @member mediaerror#media_err_custom * @constant {number} * @default 0 */ /** * w3c error code for any custom error. * * @member mediaerror.media_err_custom * @constant {number} * @default 0 */ /** * w3c error code for media error aborted. * * @member mediaerror#media_err_aborted * @constant {number} * @default 1 */ /** * w3c error code for media error aborted. * * @member mediaerror.media_err_aborted * @constant {number} * @default 1 */ /** * w3c error code for any network error. * * @member mediaerror#media_err_network * @constant {number} * @default 2 */ /** * w3c error code for any network error. * * @member mediaerror.media_err_network * @constant {number} * @default 2 */ /** * w3c error code for any decoding error. * * @member mediaerror#media_err_decode * @constant {number} * @default 3 */ /** * w3c error code for any decoding error. * * @member mediaerror.media_err_decode * @constant {number} * @default 3 */ /** * w3c error code for any time that a source is not supported. * * @member mediaerror#media_err_src_not_supported * @constant {number} * @default 4 */ /** * w3c error code for any time that a source is not supported. * * @member mediaerror.media_err_src_not_supported * @constant {number} * @default 4 */ /** * w3c error code for any time that a source is encrypted. * * @member mediaerror#media_err_encrypted * @constant {number} * @default 5 */ /** * w3c error code for any time that a source is encrypted. * * @member mediaerror.media_err_encrypted * @constant {number} * @default 5 */ exports['default'] = mediaerror; },{"88":88}],47:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _clickablecomponent = _dereq_(3); var _clickablecomponent2 = _interoprequiredefault(_clickablecomponent); var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); var _menu = _dereq_(49); var _menu2 = _interoprequiredefault(_menu); var _dom = _dereq_(81); var dom = _interoprequirewildcard(_dom); var _fn = _dereq_(83); var fn = _interoprequirewildcard(_fn); var _totitlecase = _dereq_(91); var _totitlecase2 = _interoprequiredefault(_totitlecase); function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file menu-button.js */ /** * a `menubutton` class for any popup {@link menu}. * * @extends clickablecomponent */ var menubutton = function (_clickablecomponent) { _inherits(menubutton, _clickablecomponent); /** * creates an instance of this class. * * @param {player} player * the `player` that this class should be attached to. * * @param {object} [options={}] * the key/value store of player options. */ function menubutton(player) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; _classcallcheck(this, menubutton); var _this = _possibleconstructorreturn(this, _clickablecomponent.call(this, player, options)); _this.update(); _this.enabled_ = true; _this.el_.setattribute('aria-haspopup', 'true'); _this.el_.setattribute('role', 'menuitem'); _this.on('keydown', _this.handlesubmenukeypress); return _this; } /** * update the menu based on the current state of its items. */ menubutton.prototype.update = function update() { var menu = this.createmenu(); if (this.menu) { this.removechild(this.menu); } this.menu = menu; this.addchild(menu); /** * track the state of the menu button * * @type {boolean} * @private */ this.buttonpressed_ = false; this.el_.setattribute('aria-expanded', 'false'); if (this.items && this.items.length <= this.hidethreshold_) { this.hide(); } else { this.show(); } }; /** * create the menu and add all items to it. * * @return {menu} * the constructed menu */ menubutton.prototype.createmenu = function createmenu() { var menu = new _menu2['default'](this.player_); /** * hide the menu if the number of items is less than or equal to this threshold. this defaults * to 0 and whenever we add items which can be hidden to the menu we'll increment it. we list * it here because every time we run `createmenu` we need to reset the value. * * @protected * @type {number} */ this.hidethreshold_ = 0; // add a title list item to the top if (this.options_.title) { var title = dom.createel('li', { classname: 'vjs-menu-title', innerhtml: (0, _totitlecase2['default'])(this.options_.title), tabindex: -1 }); this.hidethreshold_ += 1; menu.children_.unshift(title); dom.insertelfirst(title, menu.contentel()); } this.items = this.createitems(); if (this.items) { // add menu items to the menu for (var i = 0; i < this.items.length; i++) { menu.additem(this.items[i]); } } return menu; }; /** * create the list of menu items. specific to each subclass. * * @abstract */ menubutton.prototype.createitems = function createitems() {}; /** * create the `menubuttons`s dom element. * * @return {element} * the element that gets created. */ menubutton.prototype.createel = function createel() { return _clickablecomponent.prototype.createel.call(this, 'div', { classname: this.buildcssclass() }); }; /** * builds the default dom `classname`. * * @return {string} * the dom `classname` for this object. */ menubutton.prototype.buildcssclass = function buildcssclass() { var menubuttonclass = 'vjs-menu-button'; // if the inline option is passed, we want to use different styles altogether. if (this.options_.inline === true) { menubuttonclass += '-inline'; } else { menubuttonclass += '-popup'; } return 'vjs-menu-button ' + menubuttonclass + ' ' + _clickablecomponent.prototype.buildcssclass.call(this); }; /** * handle a click on a `menubutton`. * see {@link clickablecomponent#handleclick} for instances where this is called. * * @param {eventtarget~event} event * the `keydown`, `tap`, or `click` event that caused this function to be * called. * * @listens tap * @listens click */ menubutton.prototype.handleclick = function handleclick(event) { // when you click the button it adds focus, which will show the menu. // so we'll remove focus when the mouse leaves the button. focus is needed // for tab navigation. this.one(this.menu.contentel(), 'mouseleave', fn.bind(this, function (e) { this.unpressbutton(); this.el_.blur(); })); if (this.buttonpressed_) { this.unpressbutton(); } else { this.pressbutton(); } }; /** * handle tab, escape, down arrow, and up arrow keys for `menubutton`. see * {@link clickablecomponent#handlekeypress} for instances where this is called. * * @param {eventtarget~event} event * the `keydown` event that caused this function to be called. * * @listens keydown */ menubutton.prototype.handlekeypress = function handlekeypress(event) { // escape (27) key or tab (9) key unpress the 'button' if (event.which === 27 || event.which === 9) { if (this.buttonpressed_) { this.unpressbutton(); } // don't preventdefault for tab key - we still want to lose focus if (event.which !== 9) { event.preventdefault(); } // up (38) key or down (40) key press the 'button' } else if (event.which === 38 || event.which === 40) { if (!this.buttonpressed_) { this.pressbutton(); event.preventdefault(); } } else { _clickablecomponent.prototype.handlekeypress.call(this, event); } }; /** * handle a `keydown` event on a sub-menu. the listener for this is added in * the constructor. * * @param {eventtarget~event} event * key press event * * @listens keydown */ menubutton.prototype.handlesubmenukeypress = function handlesubmenukeypress(event) { // escape (27) key or tab (9) key unpress the 'button' if (event.which === 27 || event.which === 9) { if (this.buttonpressed_) { this.unpressbutton(); } // don't preventdefault for tab key - we still want to lose focus if (event.which !== 9) { event.preventdefault(); } } }; /** * put the current `menubutton` into a pressed state. */ menubutton.prototype.pressbutton = function pressbutton() { if (this.enabled_) { this.buttonpressed_ = true; this.menu.lockshowing(); this.el_.setattribute('aria-expanded', 'true'); // set the focus into the submenu this.menu.focus(); } }; /** * take the current `menubutton` out of a pressed state. */ menubutton.prototype.unpressbutton = function unpressbutton() { if (this.enabled_) { this.buttonpressed_ = false; this.menu.unlockshowing(); this.el_.setattribute('aria-expanded', 'false'); // set focus back to this menu button this.el_.focus(); } }; /** * disable the `menubutton`. don't allow it to be clicked. * * @return {menubutton} * returns itself; method can be chained. */ menubutton.prototype.disable = function disable() { // unpress, but don't force focus on this button this.buttonpressed_ = false; this.menu.unlockshowing(); this.el_.setattribute('aria-expanded', 'false'); this.enabled_ = false; return _clickablecomponent.prototype.disable.call(this); }; /** * enable the `menubutton`. allow it to be clicked. * * @return {menubutton} * returns itself; method can be chained. */ menubutton.prototype.enable = function enable() { this.enabled_ = true; return _clickablecomponent.prototype.enable.call(this); }; return menubutton; }(_clickablecomponent2['default']); _component2['default'].registercomponent('menubutton', menubutton); exports['default'] = menubutton; },{"3":3,"49":49,"5":5,"81":81,"83":83,"91":91}],48:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _clickablecomponent = _dereq_(3); var _clickablecomponent2 = _interoprequiredefault(_clickablecomponent); var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); var _obj = _dereq_(88); function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file menu-item.js */ /** * the component for a menu item. `
  • ` * * @extends clickablecomponent */ var menuitem = function (_clickablecomponent) { _inherits(menuitem, _clickablecomponent); /** * creates an instance of the this class. * * @param {player} player * the `player` that this class should be attached to. * * @param {object} [options={}] * the key/value store of player options. * */ function menuitem(player, options) { _classcallcheck(this, menuitem); var _this = _possibleconstructorreturn(this, _clickablecomponent.call(this, player, options)); _this.selectable = options.selectable; _this.selected(options.selected); if (_this.selectable) { // todo: may need to be either menuitemcheckbox or menuitemradio, // and may need logical grouping of menu items. _this.el_.setattribute('role', 'menuitemcheckbox'); } else { _this.el_.setattribute('role', 'menuitem'); } return _this; } /** * create the `menuitem's dom element * * @param {string} [type=li] * element's node type, not actually used, always set to `li`. * * @param {object} [props={}] * an object of properties that should be set on the element * * @param {object} [attrs={}] * an object of attributes that should be set on the element * * @return {element} * the element that gets created. */ menuitem.prototype.createel = function createel(type, props, attrs) { // the control is textual, not just an icon this.noniconcontrol = true; return _clickablecomponent.prototype.createel.call(this, 'li', (0, _obj.assign)({ classname: 'vjs-menu-item', innerhtml: this.localize(this.options_.label), tabindex: -1 }, props), attrs); }; /** * any click on a `menuitem` puts int into the selected state. * see {@link clickablecomponent#handleclick} for instances where this is called. * * @param {eventtarget~event} event * the `keydown`, `tap`, or `click` event that caused this function to be * called. * * @listens tap * @listens click */ menuitem.prototype.handleclick = function handleclick(event) { this.selected(true); }; /** * set the state for this menu item as selected or not. * * @param {boolean} selected * if the menu item is selected or not */ menuitem.prototype.selected = function selected(_selected) { if (this.selectable) { if (_selected) { this.addclass('vjs-selected'); this.el_.setattribute('aria-checked', 'true'); // aria-checked isn't fully supported by browsers/screen readers, // so indicate selected state to screen reader in the control text. this.controltext(', selected'); } else { this.removeclass('vjs-selected'); this.el_.setattribute('aria-checked', 'false'); // indicate un-selected state to screen reader // note that a space clears out the selected state text this.controltext(' '); } } }; return menuitem; }(_clickablecomponent2['default']); _component2['default'].registercomponent('menuitem', menuitem); exports['default'] = menuitem; },{"3":3,"5":5,"88":88}],49:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); var _dom = _dereq_(81); var dom = _interoprequirewildcard(_dom); var _fn = _dereq_(83); var fn = _interoprequirewildcard(_fn); var _events = _dereq_(82); var events = _interoprequirewildcard(_events); function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file menu.js */ /** * the menu component is used to build popup menus, including subtitle and * captions selection menus. * * @extends component */ var menu = function (_component) { _inherits(menu, _component); /** * create an instance of this class. * * @param {player} player * the player that this component should attach to * * @param {object} [options] * object of option names and values * */ function menu(player, options) { _classcallcheck(this, menu); var _this = _possibleconstructorreturn(this, _component.call(this, player, options)); _this.focusedchild_ = -1; _this.on('keydown', _this.handlekeypress); return _this; } /** * add a {@link menuitem} to the menu. * * @param {object|string} component * the name or instance of the `menuitem` to add. * */ menu.prototype.additem = function additem(component) { this.addchild(component); component.on('click', fn.bind(this, function (event) { this.unlockshowing(); // todo: need to set keyboard focus back to the menubutton })); }; /** * create the `menu`s dom element. * * @return {element} * the element that was created */ menu.prototype.createel = function createel() { var contenteltype = this.options_.contenteltype || 'ul'; this.contentel_ = dom.createel(contenteltype, { classname: 'vjs-menu-content' }); this.contentel_.setattribute('role', 'menu'); var el = _component.prototype.createel.call(this, 'div', { append: this.contentel_, classname: 'vjs-menu' }); el.setattribute('role', 'presentation'); el.appendchild(this.contentel_); // prevent clicks from bubbling up. needed for menu buttons, // where a click on the parent is significant events.on(el, 'click', function (event) { event.preventdefault(); event.stopimmediatepropagation(); }); return el; }; /** * handle a `keydown` event on this menu. this listener is added in the constructor. * * @param {eventtarget~event} event * a `keydown` event that happened on the menu. * * @listens keydown */ menu.prototype.handlekeypress = function handlekeypress(event) { // left and down arrows if (event.which === 37 || event.which === 40) { event.preventdefault(); this.stepforward(); // up and right arrows } else if (event.which === 38 || event.which === 39) { event.preventdefault(); this.stepback(); } }; /** * move to next (lower) menu item for keyboard users. */ menu.prototype.stepforward = function stepforward() { var stepchild = 0; if (this.focusedchild_ !== undefined) { stepchild = this.focusedchild_ + 1; } this.focus(stepchild); }; /** * move to previous (higher) menu item for keyboard users. */ menu.prototype.stepback = function stepback() { var stepchild = 0; if (this.focusedchild_ !== undefined) { stepchild = this.focusedchild_ - 1; } this.focus(stepchild); }; /** * set focus on a {@link menuitem} in the `menu`. * * @param {object|string} [item=0] * index of child item set focus on. */ menu.prototype.focus = function focus() { var item = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; var children = this.children().slice(); var havetitle = children.length && children[0].classname && /vjs-menu-title/.test(children[0].classname); if (havetitle) { children.shift(); } if (children.length > 0) { if (item < 0) { item = 0; } else if (item >= children.length) { item = children.length - 1; } this.focusedchild_ = item; children[item].el_.focus(); } }; return menu; }(_component2['default']); _component2['default'].registercomponent('menu', menu); exports['default'] = menu; },{"5":5,"81":81,"82":82,"83":83}],50:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _dom = _dereq_(81); var dom = _interoprequirewildcard(_dom); var _fn = _dereq_(83); var fn = _interoprequirewildcard(_fn); var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file modal-dialog.js */ var modal_class_name = 'vjs-modal-dialog'; var esc = 27; /** * the `modaldialog` displays over the video and its controls, which blocks * interaction with the player until it is closed. * * modal dialogs include a "close" button and will close when that button * is activated - or when esc is pressed anywhere. * * @extends component */ var modaldialog = function (_component) { _inherits(modaldialog, _component); /** * create an instance of this class. * * @param {player} player * the `player` that this class should be attached to. * * @param {object} [options] * the key/value store of player options. * * @param {mixed} [options.content=undefined] * provide customized content for this modal. * * @param {string} [options.description] * a text description for the modal, primarily for accessibility. * * @param {boolean} [options.fillalways=false] * normally, modals are automatically filled only the first time * they open. this tells the modal to refresh its content * every time it opens. * * @param {string} [options.label] * a text label for the modal, primarily for accessibility. * * @param {boolean} [options.temporary=true] * if `true`, the modal can only be opened once; it will be * disposed as soon as it's closed. * * @param {boolean} [options.uncloseable=false] * if `true`, the user will not be able to close the modal * through the ui in the normal ways. programmatic closing is * still possible. */ function modaldialog(player, options) { _classcallcheck(this, modaldialog); var _this = _possibleconstructorreturn(this, _component.call(this, player, options)); _this.opened_ = _this.hasbeenopened_ = _this.hasbeenfilled_ = false; _this.closeable(!_this.options_.uncloseable); _this.content(_this.options_.content); // make sure the contentel is defined after any children are initialized // because we only want the contents of the modal in the contentel // (not the ui elements like the close button). _this.contentel_ = dom.createel('div', { classname: modal_class_name + '-content' }, { role: 'document' }); _this.descel_ = dom.createel('p', { classname: modal_class_name + '-description vjs-offscreen', id: _this.el().getattribute('aria-describedby') }); dom.textcontent(_this.descel_, _this.description()); _this.el_.appendchild(_this.descel_); _this.el_.appendchild(_this.contentel_); return _this; } /** * create the `modaldialog`'s dom element * * @return {element} * the dom element that gets created. */ modaldialog.prototype.createel = function createel() { return _component.prototype.createel.call(this, 'div', { classname: this.buildcssclass(), tabindex: -1 }, { 'aria-describedby': this.id() + '_description', 'aria-hidden': 'true', 'aria-label': this.label(), 'role': 'dialog' }); }; /** * builds the default dom `classname`. * * @return {string} * the dom `classname` for this object. */ modaldialog.prototype.buildcssclass = function buildcssclass() { return modal_class_name + ' vjs-hidden ' + _component.prototype.buildcssclass.call(this); }; /** * handles `keydown` events on the document, looking for esc, which closes * the modal. * * @param {eventtarget~event} e * the keypress that triggered this event. * * @listens keydown */ modaldialog.prototype.handlekeypress = function handlekeypress(e) { if (e.which === esc && this.closeable()) { this.close(); } }; /** * returns the label string for this modal. primarily used for accessibility. * * @return {string} * the localized or raw label of this modal. */ modaldialog.prototype.label = function label() { return this.options_.label || this.localize('modal window'); }; /** * returns the description string for this modal. primarily used for * accessibility. * * @return {string} * the localized or raw description of this modal. */ modaldialog.prototype.description = function description() { var desc = this.options_.description || this.localize('this is a modal window.'); // append a universal closeability message if the modal is closeable. if (this.closeable()) { desc += ' ' + this.localize('this modal can be closed by pressing the escape key or activating the close button.'); } return desc; }; /** * opens the modal. * * @fires modaldialog#beforemodalopen * @fires modaldialog#modalopen * * @return {modaldialog} * returns itself; method can be chained. */ modaldialog.prototype.open = function open() { if (!this.opened_) { var player = this.player(); /** * fired just before a `modaldialog` is opened. * * @event modaldialog#beforemodalopen * @type {eventtarget~event} */ this.trigger('beforemodalopen'); this.opened_ = true; // fill content if the modal has never opened before and // never been filled. if (this.options_.fillalways || !this.hasbeenopened_ && !this.hasbeenfilled_) { this.fill(); } // if the player was playing, pause it and take note of its previously // playing state. this.wasplaying_ = !player.paused(); if (this.options_.pauseonopen && this.wasplaying_) { player.pause(); } if (this.closeable()) { this.on(this.el_.ownerdocument, 'keydown', fn.bind(this, this.handlekeypress)); } player.controls(false); this.show(); this.el().setattribute('aria-hidden', 'false'); /** * fired just after a `modaldialog` is opened. * * @event modaldialog#modalopen * @type {eventtarget~event} */ this.trigger('modalopen'); this.hasbeenopened_ = true; } return this; }; /** * if the `modaldialog` is currently open or closed. * * @param {boolean} [value] * if given, it will open (`true`) or close (`false`) the modal. * * @return {boolean} * the current open state of the modaldialog */ modaldialog.prototype.opened = function opened(value) { if (typeof value === 'boolean') { this[value ? 'open' : 'close'](); } return this.opened_; }; /** * closes the modal, does nothing if the `modaldialog` is * not open. * * @fires modaldialog#beforemodalclose * @fires modaldialog#modalclose * * @return {modaldialog} * returns itself; method can be chained. */ modaldialog.prototype.close = function close() { if (this.opened_) { var player = this.player(); /** * fired just before a `modaldialog` is closed. * * @event modaldialog#beforemodalclose * @type {eventtarget~event} */ this.trigger('beforemodalclose'); this.opened_ = false; if (this.wasplaying_ && this.options_.pauseonopen) { player.play(); } if (this.closeable()) { this.off(this.el_.ownerdocument, 'keydown', fn.bind(this, this.handlekeypress)); } player.controls(true); this.hide(); this.el().setattribute('aria-hidden', 'true'); /** * fired just after a `modaldialog` is closed. * * @event modaldialog#modalclose * @type {eventtarget~event} */ this.trigger('modalclose'); if (this.options_.temporary) { this.dispose(); } } return this; }; /** * check to see if the `modaldialog` is closeable via the ui. * * @param {boolean} [value] * if given as a boolean, it will set the `closeable` option. * * @return {boolean} * returns the final value of the closable option. */ modaldialog.prototype.closeable = function closeable(value) { if (typeof value === 'boolean') { var closeable = this.closeable_ = !!value; var close = this.getchild('closebutton'); // if this is being made closeable and has no close button, add one. if (closeable && !close) { // the close button should be a child of the modal - not its // content element, so temporarily change the content element. var temp = this.contentel_; this.contentel_ = this.el_; close = this.addchild('closebutton', { controltext: 'close modal dialog' }); this.contentel_ = temp; this.on(close, 'close', this.close); } // if this is being made uncloseable and has a close button, remove it. if (!closeable && close) { this.off(close, 'close', this.close); this.removechild(close); close.dispose(); } } return this.closeable_; }; /** * fill the modal's content element with the modal's "content" option. * the content element will be emptied before this change takes place. * * @return {modaldialog} * returns itself; method can be chained. */ modaldialog.prototype.fill = function fill() { return this.fillwith(this.content()); }; /** * fill the modal's content element with arbitrary content. * the content element will be emptied before this change takes place. * * @fires modaldialog#beforemodalfill * @fires modaldialog#modalfill * * @param {mixed} [content] * the same rules apply to this as apply to the `content` option. * * @return {modaldialog} * returns itself; method can be chained. */ modaldialog.prototype.fillwith = function fillwith(content) { var contentel = this.contentel(); var parentel = contentel.parentnode; var nextsiblingel = contentel.nextsibling; /** * fired just before a `modaldialog` is filled with content. * * @event modaldialog#beforemodalfill * @type {eventtarget~event} */ this.trigger('beforemodalfill'); this.hasbeenfilled_ = true; // detach the content element from the dom before performing // manipulation to avoid modifying the live dom multiple times. parentel.removechild(contentel); this.empty(); dom.insertcontent(contentel, content); /** * fired just after a `modaldialog` is filled with content. * * @event modaldialog#modalfill * @type {eventtarget~event} */ this.trigger('modalfill'); // re-inject the re-filled content element. if (nextsiblingel) { parentel.insertbefore(contentel, nextsiblingel); } else { parentel.appendchild(contentel); } return this; }; /** * empties the content element. this happens anytime the modal is filled. * * @fires modaldialog#beforemodalempty * @fires modaldialog#modalempty * * @return {modaldialog} * returns itself; method can be chained. */ modaldialog.prototype.empty = function empty() { /** * fired just before a `modaldialog` is emptied. * * @event modaldialog#beforemodalempty * @type {eventtarget~event} */ this.trigger('beforemodalempty'); dom.emptyel(this.contentel()); /** * fired just after a `modaldialog` is emptied. * * @event modaldialog#modalempty * @type {eventtarget~event} */ this.trigger('modalempty'); return this; }; /** * gets or sets the modal content, which gets normalized before being * rendered into the dom. * * this does not update the dom or fill the modal, but it is called during * that process. * * @param {mixed} [value] * if defined, sets the internal content value to be used on the * next call(s) to `fill`. this value is normalized before being * inserted. to "clear" the internal content value, pass `null`. * * @return {mixed} * the current content of the modal dialog */ modaldialog.prototype.content = function content(value) { if (typeof value !== 'undefined') { this.content_ = value; } return this.content_; }; return modaldialog; }(_component2['default']); /** * default options for `modaldialog` default options. * * @type {object} * @private */ modaldialog.prototype.options_ = { pauseonopen: true, temporary: true }; _component2['default'].registercomponent('modaldialog', modaldialog); exports['default'] = modaldialog; },{"5":5,"81":81,"83":83}],51:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); var _document = _dereq_(94); var _document2 = _interoprequiredefault(_document); var _window = _dereq_(95); var _window2 = _interoprequiredefault(_window); var _events = _dereq_(82); var events = _interoprequirewildcard(_events); var _dom = _dereq_(81); var dom = _interoprequirewildcard(_dom); var _fn = _dereq_(83); var fn = _interoprequirewildcard(_fn); var _guid = _dereq_(85); var guid = _interoprequirewildcard(_guid); var _browser = _dereq_(78); var browser = _interoprequirewildcard(_browser); var _log = _dereq_(86); var _log2 = _interoprequiredefault(_log); var _totitlecase = _dereq_(91); var _totitlecase2 = _interoprequiredefault(_totitlecase); var _timeranges = _dereq_(90); var _buffer = _dereq_(79); var _stylesheet = _dereq_(89); var stylesheet = _interoprequirewildcard(_stylesheet); var _fullscreenapi = _dereq_(44); var _fullscreenapi2 = _interoprequiredefault(_fullscreenapi); var _mediaerror = _dereq_(46); var _mediaerror2 = _interoprequiredefault(_mediaerror); var _tuple = _dereq_(97); var _tuple2 = _interoprequiredefault(_tuple); var _obj = _dereq_(88); var _mergeoptions = _dereq_(87); var _mergeoptions2 = _interoprequiredefault(_mergeoptions); var _texttracklistconverter = _dereq_(69); var _texttracklistconverter2 = _interoprequiredefault(_texttracklistconverter); var _modaldialog = _dereq_(50); var _modaldialog2 = _interoprequiredefault(_modaldialog); var _tech = _dereq_(62); var _tech2 = _interoprequiredefault(_tech); var _audiotracklist = _dereq_(63); var _audiotracklist2 = _interoprequiredefault(_audiotracklist); var _videotracklist = _dereq_(76); var _videotracklist2 = _interoprequiredefault(_videotracklist); _dereq_(61); _dereq_(59); _dereq_(55); _dereq_(68); _dereq_(45); _dereq_(1); _dereq_(4); _dereq_(8); _dereq_(41); _dereq_(71); _dereq_(60); function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file player.js */ // subclasses component // the following imports are used only to ensure that the corresponding modules // are always included in the video.js package. importing the modules will // execute them and they will register themselves with video.js. // import html5 tech, at least for disposing the original video tag. // the following tech events are simply re-triggered // on the player when they happen var tech_events_retrigger = [ /** * fired while the user agent is downloading media data. * * @event player#progress * @type {eventtarget~event} */ /** * retrigger the `progress` event that was triggered by the {@link tech}. * * @private * @method player#handletechprogress_ * @fires player#progress * @listens tech#progress */ 'progress', /** * fires when the loading of an audio/video is aborted. * * @event player#abort * @type {eventtarget~event} */ /** * retrigger the `abort` event that was triggered by the {@link tech}. * * @private * @method player#handletechabort_ * @fires player#abort * @listens tech#abort */ 'abort', /** * fires when the browser is intentionally not getting media data. * * @event player#suspend * @type {eventtarget~event} */ /** * retrigger the `suspend` event that was triggered by the {@link tech}. * * @private * @method player#handletechsuspend_ * @fires player#suspend * @listens tech#suspend */ 'suspend', /** * fires when the current playlist is empty. * * @event player#emptied * @type {eventtarget~event} */ /** * retrigger the `emptied` event that was triggered by the {@link tech}. * * @private * @method player#handletechemptied_ * @fires player#emptied * @listens tech#emptied */ 'emptied', /** * fires when the browser is trying to get media data, but data is not available. * * @event player#stalled * @type {eventtarget~event} */ /** * retrigger the `stalled` event that was triggered by the {@link tech}. * * @private * @method player#handletechstalled_ * @fires player#stalled * @listens tech#stalled */ 'stalled', /** * fires when the browser has loaded meta data for the audio/video. * * @event player#loadedmetadata * @type {eventtarget~event} */ /** * retrigger the `stalled` event that was triggered by the {@link tech}. * * @private * @method player#handletechloadedmetadata_ * @fires player#loadedmetadata * @listens tech#loadedmetadata */ 'loadedmetadata', /** * fires when the browser has loaded the current frame of the audio/video. * * @event player#loadeddata * @type {event} */ /** * retrigger the `loadeddata` event that was triggered by the {@link tech}. * * @private * @method player#handletechloaddeddata_ * @fires player#loadeddata * @listens tech#loadeddata */ 'loadeddata', /** * fires when the current playback position has changed. * * @event player#timeupdate * @type {event} */ /** * retrigger the `timeupdate` event that was triggered by the {@link tech}. * * @private * @method player#handletechtimeupdate_ * @fires player#timeupdate * @listens tech#timeupdate */ 'timeupdate', /** * fires when the playing speed of the audio/video is changed * * @event player#ratechange * @type {event} */ /** * retrigger the `ratechange` event that was triggered by the {@link tech}. * * @private * @method player#handletechratechange_ * @fires player#ratechange * @listens tech#ratechange */ 'ratechange', /** * fires when the volume has been changed * * @event player#volumechange * @type {event} */ /** * retrigger the `volumechange` event that was triggered by the {@link tech}. * * @private * @method player#handletechvolumechange_ * @fires player#volumechange * @listens tech#volumechange */ 'volumechange', /** * fires when the text track has been changed * * @event player#texttrackchange * @type {event} */ /** * retrigger the `texttrackchange` event that was triggered by the {@link tech}. * * @private * @method player#handletechtexttrackchange_ * @fires player#texttrackchange * @listens tech#texttrackchange */ 'texttrackchange']; /** * an instance of the `player` class is created when any of the video.js setup methods * are used to initialize a video. * * after an instance has been created it can be accessed globally in two ways: * 1. by calling `videojs('example_video_1');` * 2. by using it directly via `videojs.players.example_video_1;` * * @extends component */ var player = function (_component) { _inherits(player, _component); /** * create an instance of this class. * * @param {element} tag * the original video dom element used for configuring options. * * @param {object} [options] * object of option names and values. * * @param {component~readycallback} [ready] * ready callback function. */ function player(tag, options, ready) { _classcallcheck(this, player); // make sure tag id exists tag.id = tag.id || 'vjs_video_' + guid.newguid(); // set options // the options argument overrides options set in the video tag // which overrides globally set options. // this latter part coincides with the load order // (tag must exist before player) options = (0, _obj.assign)(player.gettagsettings(tag), options); // delay the initialization of children because we need to set up // player properties first, and can't use `this` before `super()` options.initchildren = false; // same with creating the element options.createel = false; // we don't want the player to report touch activity on itself // see enabletouchactivity in component options.reporttouchactivity = false; // if language is not set, get the closest lang attribute if (!options.language) { if (typeof tag.closest === 'function') { var closest = tag.closest('[lang]'); if (closest) { options.language = closest.getattribute('lang'); } } else { var element = tag; while (element && element.nodetype === 1) { if (dom.getelattributes(element).hasownproperty('lang')) { options.language = element.getattribute('lang'); break; } element = element.parentnode; } } } // run base component initializing with new options // if the global option object was accidentally blown away by // someone, bail early with an informative error var _this = _possibleconstructorreturn(this, _component.call(this, null, options, ready)); if (!_this.options_ || !_this.options_.techorder || !_this.options_.techorder.length) { throw new error('no techorder specified. did you overwrite ' + 'videojs.options instead of just changing the ' + 'properties you want to override?'); } // store the original tag used to set options _this.tag = tag; // store the tag attributes used to restore html5 element _this.tagattributes = tag && dom.getelattributes(tag); // update current language _this.language(_this.options_.language); // update supported languages if (options.languages) { // normalise player option languages to lowercase var languagestolower = {}; object.getownpropertynames(options.languages).foreach(function (name) { languagestolower[name.tolowercase()] = options.languages[name]; }); _this.languages_ = languagestolower; } else { _this.languages_ = player.prototype.options_.languages; } // cache for video property values. _this.cache_ = {}; // set poster _this.poster_ = options.poster || ''; // set controls _this.controls_ = !!options.controls; // original tag settings stored in options // now remove immediately so native controls don't flash. // may be turned back on by html5 tech if nativecontrolsfortouch is true tag.controls = false; /* * store the internal state of scrubbing * * @private * @return {boolean} true if the user is scrubbing */ _this.scrubbing_ = false; _this.el_ = _this.createel(); // we also want to pass the original player options to each component and plugin // as well so they don't need to reach back into the player for options later. // we also need to do another copy of this.options_ so we don't end up with // an infinite loop. var playeroptionscopy = (0, _mergeoptions2['default'])(_this.options_); // load plugins if (options.plugins) { var plugins = options.plugins; object.getownpropertynames(plugins).foreach(function (name) { if (typeof this[name] === 'function') { this[name](plugins[name]); } else { _log2['default'].error('unable to find plugin:', name); } }, _this); } _this.options_.playeroptions = playeroptionscopy; _this.initchildren(); // set isaudio based on whether or not an audio tag was used _this.isaudio(tag.nodename.tolowercase() === 'audio'); // update controls classname. can't do this when the controls are initially // set because the element doesn't exist yet. if (_this.controls()) { _this.addclass('vjs-controls-enabled'); } else { _this.addclass('vjs-controls-disabled'); } // set aria label and region role depending on player type _this.el_.setattribute('role', 'region'); if (_this.isaudio()) { _this.el_.setattribute('aria-label', 'audio player'); } else { _this.el_.setattribute('aria-label', 'video player'); } if (_this.isaudio()) { _this.addclass('vjs-audio'); } if (_this.flexnotsupported_()) { _this.addclass('vjs-no-flex'); } // todo: make this smarter. toggle user state between touching/mousing // using events, since devices can have both touch and mouse events. // if (browser.touch_enabled) { // this.addclass('vjs-touch-enabled'); // } // ios safari has broken hover handling if (!browser.is_ios) { _this.addclass('vjs-workinghover'); } // make player easily findable by id player.players[_this.id_] = _this; // when the player is first initialized, trigger activity so components // like the control bar show themselves if needed _this.useractive(true); _this.reportuseractivity(); _this.listenforuseractivity_(); _this.on('fullscreenchange', _this.handlefullscreenchange_); _this.on('stageclick', _this.handlestageclick_); return _this; } /** * destroys the video player and does any necessary cleanup. * * this is especially helpful if you are dynamically adding and removing videos * to/from the dom. * * @fires player#dispose */ player.prototype.dispose = function dispose() { /** * called when the player is being disposed of. * * @event player#dispose * @type {eventtarget~event} */ this.trigger('dispose'); // prevent dispose from being called twice this.off('dispose'); if (this.styleel_ && this.styleel_.parentnode) { this.styleel_.parentnode.removechild(this.styleel_); } // kill reference to this player player.players[this.id_] = null; if (this.tag && this.tag.player) { this.tag.player = null; } if (this.el_ && this.el_.player) { this.el_.player = null; } if (this.tech_) { this.tech_.dispose(); } _component.prototype.dispose.call(this); }; /** * create the `player`'s dom element. * * @return {element} * the dom element that gets created. */ player.prototype.createel = function createel() { var tag = this.tag; var el = void 0; var playerelingest = this.playerelingest_ = tag.parentnode && tag.parentnode.hasattribute && tag.parentnode.hasattribute('data-vjs-player'); if (playerelingest) { el = this.el_ = tag.parentnode; } else { el = this.el_ = _component.prototype.createel.call(this, 'div'); } // set tabindex to -1 so we could focus on the player element tag.setattribute('tabindex', '-1'); // remove width/height attrs from tag so css can make it 100% width/height tag.removeattribute('width'); tag.removeattribute('height'); // copy over all the attributes from the tag, including id and class // id will now reference player box, not the video tag var attrs = dom.getelattributes(tag); object.getownpropertynames(attrs).foreach(function (attr) { // workaround so we don't totally break ie7 // http://stackoverflow.com/questions/3653444/css-styles-not-applied-on-dynamic-elements-in-internet-explorer-7 if (attr === 'class') { el.classname += ' ' + attrs[attr]; } else { el.setattribute(attr, attrs[attr]); } }); // update tag id/class for use as html5 playback tech // might think we should do this after embedding in container so .vjs-tech class // doesn't flash 100% width/height, but class only applies with .video-js parent tag.playerid = tag.id; tag.id += '_html5_api'; tag.classname = 'vjs-tech'; // make player findable on elements tag.player = el.player = this; // default state of video is paused this.addclass('vjs-paused'); // add a style element in the player that we'll use to set the width/height // of the player in a way that's still overrideable by css, just like the // video element if (_window2['default'].videojs_no_dynamic_style !== true) { this.styleel_ = stylesheet.createstyleelement('vjs-styles-dimensions'); var defaultsstyleel = dom.$('.vjs-styles-defaults'); var head = dom.$('head'); head.insertbefore(this.styleel_, defaultsstyleel ? defaultsstyleel.nextsibling : head.firstchild); } // pass in the width/height/aspectratio options which will update the style el this.width(this.options_.width); this.height(this.options_.height); this.fluid(this.options_.fluid); this.aspectratio(this.options_.aspectratio); // hide any links within the video/audio tag, because ie doesn't hide them completely. var links = tag.getelementsbytagname('a'); for (var i = 0; i < links.length; i++) { var linkel = links.item(i); dom.addelclass(linkel, 'vjs-hidden'); linkel.setattribute('hidden', 'hidden'); } // insertelfirst seems to cause the networkstate to flicker from 3 to 2, so // keep track of the original for later so we can know if the source originally failed tag.initnetworkstate_ = tag.networkstate; // wrap video tag in div (el/box) container if (tag.parentnode && !playerelingest) { tag.parentnode.insertbefore(el, tag); } // insert the tag as the first child of the player element // then manually add it to the children array so that this.addchild // will work properly for other components // // breaks iphone, fixed in html5 setup. dom.insertelfirst(tag, el); this.children_.unshift(tag); this.el_ = el; return el; }; /** * a getter/setter for the `player`'s width. * * @param {number} [value] * the value to set the `player's width to. * * @return {number} * the current width of the `player`. */ player.prototype.width = function width(value) { return this.dimension('width', value); }; /** * a getter/setter for the `player`'s height. * * @param {number} [value] * the value to set the `player's heigth to. * * @return {number} * the current heigth of the `player`. */ player.prototype.height = function height(value) { return this.dimension('height', value); }; /** * a getter/setter for the `player`'s width & height. * * @param {string} dimension * this string can be: * - 'width' * - 'height' * * @param {number} [value] * value for dimension specified in the first argument. * * @return {player|number} * - returns itself when setting; method can be chained. * - the dimension arguments value when getting (width/height). */ player.prototype.dimension = function dimension(_dimension, value) { var privdimension = _dimension + '_'; if (value === undefined) { return this[privdimension] || 0; } if (value === '') { // if an empty string is given, reset the dimension to be automatic this[privdimension] = undefined; } else { var parsedval = parsefloat(value); if (isnan(parsedval)) { _log2['default'].error('improper value "' + value + '" supplied for for ' + _dimension); return this; } this[privdimension] = parsedval; } this.updatestyleel_(); return this; }; /** * a getter/setter/toggler for the vjs-fluid `classname` on the `player`. * * @param {boolean} [bool] * - a value of true adds the class. * - a value of false removes the class. * - no value will toggle the fluid class. * * @return {boolean|undefined} * - the value of fluid when getting. * - `undefined` when setting. */ player.prototype.fluid = function fluid(bool) { if (bool === undefined) { return !!this.fluid_; } this.fluid_ = !!bool; if (bool) { this.addclass('vjs-fluid'); } else { this.removeclass('vjs-fluid'); } this.updatestyleel_(); }; /** * get/set the aspect ratio * * @param {string} [ratio] * aspect ratio for player * * @return {string|undefined} * returns the current aspect ratio when getting */ /** * a getter/setter for the `player`'s aspect ratio. * * @param {string} [ratio] * the value to set the `player's aspect ratio to. * * @return {string|undefined} * - the current aspect ratio of the `player` when getting. * - undefined when setting */ player.prototype.aspectratio = function aspectratio(ratio) { if (ratio === undefined) { return this.aspectratio_; } // check for width:height format if (!/^\d+\:\d+$/.test(ratio)) { throw new error('improper value supplied for aspect ratio. the format should be width:height, for example 16:9.'); } this.aspectratio_ = ratio; // we're assuming if you set an aspect ratio you want fluid mode, // because in fixed mode you could calculate width and height yourself. this.fluid(true); this.updatestyleel_(); }; /** * update styles of the `player` element (height, width and aspect ratio). * * @private * @listens tech#loadedmetadata */ player.prototype.updatestyleel_ = function updatestyleel_() { if (_window2['default'].videojs_no_dynamic_style === true) { var _width = typeof this.width_ === 'number' ? this.width_ : this.options_.width; var _height = typeof this.height_ === 'number' ? this.height_ : this.options_.height; var techel = this.tech_ && this.tech_.el(); if (techel) { if (_width >= 0) { techel.width = _width; } if (_height >= 0) { techel.height = _height; } } return; } var width = void 0; var height = void 0; var aspectratio = void 0; var idclass = void 0; // the aspect ratio is either used directly or to calculate width and height. if (this.aspectratio_ !== undefined && this.aspectratio_ !== 'auto') { // use any aspectratio that's been specifically set aspectratio = this.aspectratio_; } else if (this.videowidth() > 0) { // otherwise try to get the aspect ratio from the video metadata aspectratio = this.videowidth() + ':' + this.videoheight(); } else { // or use a default. the video element's is 2:1, but 16:9 is more common. aspectratio = '16:9'; } // get the ratio as a decimal we can use to calculate dimensions var ratioparts = aspectratio.split(':'); var ratiomultiplier = ratioparts[1] / ratioparts[0]; if (this.width_ !== undefined) { // use any width that's been specifically set width = this.width_; } else if (this.height_ !== undefined) { // or calulate the width from the aspect ratio if a height has been set width = this.height_ / ratiomultiplier; } else { // or use the video's metadata, or use the video el's default of 300 width = this.videowidth() || 300; } if (this.height_ !== undefined) { // use any height that's been specifically set height = this.height_; } else { // otherwise calculate the height from the ratio and the width height = width * ratiomultiplier; } // ensure the css class is valid by starting with an alpha character if (/^[^a-za-z]/.test(this.id())) { idclass = 'dimensions-' + this.id(); } else { idclass = this.id() + '-dimensions'; } // ensure the right class is still on the player for the style element this.addclass(idclass); stylesheet.settextcontent(this.styleel_, '\n .' + idclass + ' {\n width: ' + width + 'px;\n height: ' + height + 'px;\n }\n\n .' + idclass + '.vjs-fluid {\n padding-top: ' + ratiomultiplier * 100 + '%;\n }\n '); }; /** * load/create an instance of playback {@link tech} including element * and api methods. then append the `tech` element in `player` as a child. * * @param {string} techname * name of the playback technology * * @param {string} source * video source * * @private */ player.prototype.loadtech_ = function loadtech_(techname, source) { var _this2 = this; // pause and remove current playback technology if (this.tech_) { this.unloadtech_(); } // get rid of the html5 video tag as soon as we are using another tech if (techname !== 'html5' && this.tag) { _tech2['default'].gettech('html5').disposemediaelement(this.tag); this.tag.player = null; this.tag = null; } this.techname_ = techname; // turn off api access because we're loading a new tech that might load asynchronously this.isready_ = false; // grab tech-specific options from player options and add source and parent element to use. var techoptions = (0, _obj.assign)({ source: source, 'nativecontrolsfortouch': this.options_.nativecontrolsfortouch, 'playerid': this.id(), 'techid': this.id() + '_' + techname + '_api', 'videotracks': this.videotracks_, 'texttracks': this.texttracks_, 'audiotracks': this.audiotracks_, 'autoplay': this.options_.autoplay, 'preload': this.options_.preload, 'loop': this.options_.loop, 'muted': this.options_.muted, 'poster': this.poster(), 'language': this.language(), 'playerelingest': this.playerelingest_ || false, 'vtt.js': this.options_['vtt.js'] }, this.options_[techname.tolowercase()]); if (this.tag) { techoptions.tag = this.tag; } if (source) { this.currenttype_ = source.type; if (source.src === this.cache_.src && this.cache_.currenttime > 0) { techoptions.starttime = this.cache_.currenttime; } this.cache_.sources = null; this.cache_.source = source; this.cache_.src = source.src; } // initialize tech instance var techcomponent = _tech2['default'].gettech(techname); // support old behavior of techs being registered as components. // remove once that deprecated behavior is removed. if (!techcomponent) { techcomponent = _component2['default'].getcomponent(techname); } this.tech_ = new techcomponent(techoptions); // player.triggerready is always async, so don't need this to be async this.tech_.ready(fn.bind(this, this.handletechready_), true); _texttracklistconverter2['default'].jsontotexttracks(this.texttracksjson_ || [], this.tech_); // listen to all html5-defined events and trigger them on the player tech_events_retrigger.foreach(function (event) { _this2.on(_this2.tech_, event, _this2['handletech' + (0, _totitlecase2['default'])(event) + '_']); }); this.on(this.tech_, 'loadstart', this.handletechloadstart_); this.on(this.tech_, 'waiting', this.handletechwaiting_); this.on(this.tech_, 'canplay', this.handletechcanplay_); this.on(this.tech_, 'canplaythrough', this.handletechcanplaythrough_); this.on(this.tech_, 'playing', this.handletechplaying_); this.on(this.tech_, 'ended', this.handletechended_); this.on(this.tech_, 'seeking', this.handletechseeking_); this.on(this.tech_, 'seeked', this.handletechseeked_); this.on(this.tech_, 'play', this.handletechplay_); this.on(this.tech_, 'firstplay', this.handletechfirstplay_); this.on(this.tech_, 'pause', this.handletechpause_); this.on(this.tech_, 'durationchange', this.handletechdurationchange_); this.on(this.tech_, 'fullscreenchange', this.handletechfullscreenchange_); this.on(this.tech_, 'error', this.handletecherror_); this.on(this.tech_, 'loadedmetadata', this.updatestyleel_); this.on(this.tech_, 'posterchange', this.handletechposterchange_); this.on(this.tech_, 'textdata', this.handletechtextdata_); this.usingnativecontrols(this.techget_('controls')); if (this.controls() && !this.usingnativecontrols()) { this.addtechcontrolslisteners_(); } // add the tech element in the dom if it was not already there // make sure to not insert the original video element if using html5 if (this.tech_.el().parentnode !== this.el() && (techname !== 'html5' || !this.tag)) { dom.insertelfirst(this.tech_.el(), this.el()); } // get rid of the original video tag reference after the first tech is loaded if (this.tag) { this.tag.player = null; this.tag = null; } }; /** * unload and dispose of the current playback {@link tech}. * * @private */ player.prototype.unloadtech_ = function unloadtech_() { // save the current text tracks so that we can reuse the same text tracks with the next tech this.videotracks_ = this.videotracks(); this.texttracks_ = this.texttracks(); this.audiotracks_ = this.audiotracks(); this.texttracksjson_ = _texttracklistconverter2['default'].texttrackstojson(this.tech_); this.isready_ = false; this.tech_.dispose(); this.tech_ = false; }; /** * return a reference to the current {@link tech}, but only if given an object with the * `iwillnotusethisinplugins` property having a true value. this is try and prevent misuse * of techs by plugins. * * @param {object} safety * an object that must contain `{iwillnotusethisinplugins: true}` * * @param {boolean} safety.iwillnotusethisinplugins * must be set to true or else this function will throw an error. * * @return {tech} * the tech */ player.prototype.tech = function tech(safety) { if (safety && safety.iwillnotusethisinplugins) { return this.tech_; } var errortext = '\n please make sure that you are not using this inside of a plugin.\n to disable this alert and error, please pass in an object with\n `iwillnotusethisinplugins` to the `tech` method. see\n https://github.com/videojs/video.js/issues/2617 for more info.\n '; _window2['default'].alert(errortext); throw new error(errortext); }; /** * set up click and touch listeners for the playback element * * - on desktops: a click on the video itself will toggle playback * - on mobile devices: a click on the video toggles controls * which is done by toggling the user state between active and * inactive * - a tap can signal that a user has become active or has become inactive * e.g. a quick tap on an iphone movie should reveal the controls. another * quick tap should hide them again (signaling the user is in an inactive * viewing state) * - in addition to this, we still want the user to be considered inactive after * a few seconds of inactivity. * * > note: the only part of ios interaction we can't mimic with this setup * is a touch and hold on the video element counting as activity in order to * keep the controls showing, but that shouldn't be an issue. a touch and hold * on any controls will still keep the user active * * @private */ player.prototype.addtechcontrolslisteners_ = function addtechcontrolslisteners_() { // make sure to remove all the previous listeners in case we are called multiple times. this.removetechcontrolslisteners_(); // some browsers (chrome & ie) don't trigger a click on a flash swf, but do // trigger mousedown/up. // http://stackoverflow.com/questions/1444562/javascript-onclick-event-over-flash-object // any touch events are set to block the mousedown event from happening this.on(this.tech_, 'mousedown', this.handletechclick_); // if the controls were hidden we don't want that to change without a tap event // so we'll check if the controls were already showing before reporting user // activity this.on(this.tech_, 'touchstart', this.handletechtouchstart_); this.on(this.tech_, 'touchmove', this.handletechtouchmove_); this.on(this.tech_, 'touchend', this.handletechtouchend_); // the tap listener needs to come after the touchend listener because the tap // listener cancels out any reporteduseractivity when setting useractive(false) this.on(this.tech_, 'tap', this.handletechtap_); }; /** * remove the listeners used for click and tap controls. this is needed for * toggling to controls disabled, where a tap/touch should do nothing. * * @private */ player.prototype.removetechcontrolslisteners_ = function removetechcontrolslisteners_() { // we don't want to just use `this.off()` because there might be other needed // listeners added by techs that extend this. this.off(this.tech_, 'tap', this.handletechtap_); this.off(this.tech_, 'touchstart', this.handletechtouchstart_); this.off(this.tech_, 'touchmove', this.handletechtouchmove_); this.off(this.tech_, 'touchend', this.handletechtouchend_); this.off(this.tech_, 'mousedown', this.handletechclick_); }; /** * player waits for the tech to be ready * * @private */ player.prototype.handletechready_ = function handletechready_() { this.triggerready(); // keep the same volume as before if (this.cache_.volume) { this.techcall_('setvolume', this.cache_.volume); } // look if the tech found a higher resolution poster while loading this.handletechposterchange_(); // update the duration if available this.handletechdurationchange_(); // chrome and safari both have issues with autoplay. // in safari (5.1.1), when we move the video element into the container div, autoplay doesn't work. // in chrome (15), if you have autoplay + a poster + no controls, the video gets hidden (but audio plays) // this fixes both issues. need to wait for api, so it updates displays correctly if ((this.src() || this.currentsrc()) && this.tag && this.options_.autoplay && this.paused()) { try { // chrome fix. fixed in chrome v16. delete this.tag.poster; } catch (e) { (0, _log2['default'])('deleting tag.poster throws in some browsers', e); } this.play(); } }; /** * retrigger the `loadstart` event that was triggered by the {@link tech}. this * function will also trigger {@link player#firstplay} if it is the first loadstart * for a video. * * @fires player#loadstart * @fires player#firstplay * @listens tech#loadstart * @private */ player.prototype.handletechloadstart_ = function handletechloadstart_() { // todo: update to use `emptied` event instead. see #1277. this.removeclass('vjs-ended'); this.removeclass('vjs-seeking'); // reset the error state this.error(null); // if it's already playing we want to trigger a firstplay event now. // the firstplay event relies on both the play and loadstart events // which can happen in any order for a new source if (!this.paused()) { /** * fired when the user agent begins looking for media data * * @event player#loadstart * @type {eventtarget~event} */ this.trigger('loadstart'); this.trigger('firstplay'); } else { // reset the hasstarted state this.hasstarted(false); this.trigger('loadstart'); } }; /** * add/remove the vjs-has-started class * * @fires player#firstplay * * @param {boolean} hasstarted * - true: adds the class * - false: remove the class * * @return {boolean} * the boolean value of hasstarted */ player.prototype.hasstarted = function hasstarted(_hasstarted) { if (_hasstarted !== undefined) { // only update if this is a new value if (this.hasstarted_ !== _hasstarted) { this.hasstarted_ = _hasstarted; if (_hasstarted) { this.addclass('vjs-has-started'); // trigger the firstplay event if this newly has played this.trigger('firstplay'); } else { this.removeclass('vjs-has-started'); } } return this; } return !!this.hasstarted_; }; /** * fired whenever the media begins or resumes playback * * @see [spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#dom-media-play} * @fires player#play * @listens tech#play * @private */ player.prototype.handletechplay_ = function handletechplay_() { this.removeclass('vjs-ended'); this.removeclass('vjs-paused'); this.addclass('vjs-playing'); // hide the poster when the user hits play this.hasstarted(true); /** * triggered whenever an {@link tech#play} event happens. indicates that * playback has started or resumed. * * @event player#play * @type {eventtarget~event} */ this.trigger('play'); }; /** * retrigger the `waiting` event that was triggered by the {@link tech}. * * @fires player#waiting * @listens tech#waiting * @private */ player.prototype.handletechwaiting_ = function handletechwaiting_() { var _this3 = this; this.addclass('vjs-waiting'); /** * a readystate change on the dom element has caused playback to stop. * * @event player#waiting * @type {eventtarget~event} */ this.trigger('waiting'); this.one('timeupdate', function () { return _this3.removeclass('vjs-waiting'); }); }; /** * retrigger the `canplay` event that was triggered by the {@link tech}. * > note: this is not consistent between browsers. see #1351 * * @fires player#canplay * @listens tech#canplay * @private */ player.prototype.handletechcanplay_ = function handletechcanplay_() { this.removeclass('vjs-waiting'); /** * the media has a readystate of have_future_data or greater. * * @event player#canplay * @type {eventtarget~event} */ this.trigger('canplay'); }; /** * retrigger the `canplaythrough` event that was triggered by the {@link tech}. * * @fires player#canplaythrough * @listens tech#canplaythrough * @private */ player.prototype.handletechcanplaythrough_ = function handletechcanplaythrough_() { this.removeclass('vjs-waiting'); /** * the media has a readystate of have_enough_data or greater. this means that the * entire media file can be played without buffering. * * @event player#canplaythrough * @type {eventtarget~event} */ this.trigger('canplaythrough'); }; /** * retrigger the `playing` event that was triggered by the {@link tech}. * * @fires player#playing * @listens tech#playing * @private */ player.prototype.handletechplaying_ = function handletechplaying_() { this.removeclass('vjs-waiting'); /** * the media is no longer blocked from playback, and has started playing. * * @event player#playing * @type {eventtarget~event} */ this.trigger('playing'); }; /** * retrigger the `seeking` event that was triggered by the {@link tech}. * * @fires player#seeking * @listens tech#seeking * @private */ player.prototype.handletechseeking_ = function handletechseeking_() { this.addclass('vjs-seeking'); /** * fired whenever the player is jumping to a new time * * @event player#seeking * @type {eventtarget~event} */ this.trigger('seeking'); }; /** * retrigger the `seeked` event that was triggered by the {@link tech}. * * @fires player#seeked * @listens tech#seeked * @private */ player.prototype.handletechseeked_ = function handletechseeked_() { this.removeclass('vjs-seeking'); /** * fired when the player has finished jumping to a new time * * @event player#seeked * @type {eventtarget~event} */ this.trigger('seeked'); }; /** * retrigger the `firstplay` event that was triggered by the {@link tech}. * * @fires player#firstplay * @listens tech#firstplay * @deprecated as of 6.0 passing the `starttime` option to the player will be deprecated * @private */ player.prototype.handletechfirstplay_ = function handletechfirstplay_() { // if the first starttime attribute is specified // then we will start at the given offset in seconds if (this.options_.starttime) { _log2['default'].warn('passing the `starttime` option to the player will be deprecated in 6.0'); this.currenttime(this.options_.starttime); } this.addclass('vjs-has-started'); /** * fired the first time a video is played. not part of the hls spec, and this is * probably not the best implementation yet, so use sparingly. if you don't have a * reason to prevent playback, use `myplayer.one('play');` instead. * * @event player#firstplay * @type {eventtarget~event} */ this.trigger('firstplay'); }; /** * retrigger the `pause` event that was triggered by the {@link tech}. * * @fires player#pause * @listens tech#pause * @private */ player.prototype.handletechpause_ = function handletechpause_() { this.removeclass('vjs-playing'); this.addclass('vjs-paused'); /** * fired whenever the media has been paused * * @event player#pause * @type {eventtarget~event} */ this.trigger('pause'); }; /** * retrigger the `ended` event that was triggered by the {@link tech}. * * @fires player#ended * @listens tech#ended * @private */ player.prototype.handletechended_ = function handletechended_() { this.addclass('vjs-ended'); if (this.options_.loop) { this.currenttime(0); this.play(); } else if (!this.paused()) { this.pause(); } /** * fired when the end of the media resource is reached (currenttime == duration) * * @event player#ended * @type {eventtarget~event} */ this.trigger('ended'); }; /** * fired when the duration of the media resource is first known or changed * * @listens tech#durationchange * @private */ player.prototype.handletechdurationchange_ = function handletechdurationchange_() { this.duration(this.techget_('duration')); }; /** * handle a click on the media element to play/pause * * @param {eventtarget~event} event * the event that caused this function to trigger * * @listens tech#mousedown * @private */ player.prototype.handletechclick_ = function handletechclick_(event) { // we're using mousedown to detect clicks thanks to flash, but mousedown // will also be triggered with right-clicks, so we need to prevent that if (event.button !== 0) { return; } // when controls are disabled a click should not toggle playback because // the click is considered a control if (this.controls()) { if (this.paused()) { this.play(); } else { this.pause(); } } }; /** * handle a tap on the media element. it will toggle the user * activity state, which hides and shows the controls. * * @listens tech#tap * @private */ player.prototype.handletechtap_ = function handletechtap_() { this.useractive(!this.useractive()); }; /** * handle touch to start * * @listens tech#touchstart * @private */ player.prototype.handletechtouchstart_ = function handletechtouchstart_() { this.userwasactive = this.useractive(); }; /** * handle touch to move * * @listens tech#touchmove * @private */ player.prototype.handletechtouchmove_ = function handletechtouchmove_() { if (this.userwasactive) { this.reportuseractivity(); } }; /** * handle touch to end * * @param {eventtarget~event} event * the touchend event that triggered * this function * * @listens tech#touchend * @private */ player.prototype.handletechtouchend_ = function handletechtouchend_(event) { // stop the mouse events from also happening event.preventdefault(); }; /** * fired when the player switches in or out of fullscreen mode * * @private * @listens player#fullscreenchange */ player.prototype.handlefullscreenchange_ = function handlefullscreenchange_() { if (this.isfullscreen()) { this.addclass('vjs-fullscreen'); } else { this.removeclass('vjs-fullscreen'); } }; /** * native click events on the swf aren't triggered on ie11, win8.1rt * use stageclick events triggered from inside the swf instead * * @private * @listens stageclick */ player.prototype.handlestageclick_ = function handlestageclick_() { this.reportuseractivity(); }; /** * handle tech fullscreen change * * @param {eventtarget~event} event * the fullscreenchange event that triggered this function * * @param {object} data * the data that was sent with the event * * @private * @listens tech#fullscreenchange * @fires player#fullscreenchange */ player.prototype.handletechfullscreenchange_ = function handletechfullscreenchange_(event, data) { if (data) { this.isfullscreen(data.isfullscreen); } /** * fired when going in and out of fullscreen. * * @event player#fullscreenchange * @type {eventtarget~event} */ this.trigger('fullscreenchange'); }; /** * fires when an error occurred during the loading of an audio/video. * * @private * @listens tech#error */ player.prototype.handletecherror_ = function handletecherror_() { var error = this.tech_.error(); this.error(error); }; /** * retrigger the `textdata` event that was triggered by the {@link tech}. * * @fires player#textdata * @listens tech#textdata * @private */ player.prototype.handletechtextdata_ = function handletechtextdata_() { var data = null; if (arguments.length > 1) { data = arguments[1]; } /** * fires when we get a textdata event from tech * * @event player#textdata * @type {eventtarget~event} */ this.trigger('textdata', data); }; /** * get object for cached values. * * @return {object} * get the current object cache */ player.prototype.getcache = function getcache() { return this.cache_; }; /** * pass values to the playback tech * * @param {string} [method] * the method to call * * @param {object} arg * the argument to pass * * @private */ player.prototype.techcall_ = function techcall_(method, arg) { // if it's not ready yet, call method when it is if (this.tech_ && !this.tech_.isready_) { this.tech_.ready(function () { this[method](arg); }, true); // otherwise call method now } else { try { if (this.tech_) { this.tech_[method](arg); } } catch (e) { (0, _log2['default'])(e); throw e; } } }; /** * get calls can't wait for the tech, and sometimes don't need to. * * @param {string} method * tech method * * @return {function|undefined} * the method or undefined * * @private */ player.prototype.techget_ = function techget_(method) { if (this.tech_ && this.tech_.isready_) { // flash likes to die and reload when you hide or reposition it. // in these cases the object methods go away and we get errors. // when that happens we'll catch the errors and inform tech that it's not ready any more. try { return this.tech_[method](); } catch (e) { // when building additional tech libs, an expected method may not be defined yet if (this.tech_[method] === undefined) { (0, _log2['default'])('video.js: ' + method + ' method not defined for ' + this.techname_ + ' playback technology.', e); // when a method isn't available on the object it throws a typeerror } else if (e.name === 'typeerror') { (0, _log2['default'])('video.js: ' + method + ' unavailable on ' + this.techname_ + ' playback technology element.', e); this.tech_.isready_ = false; } else { (0, _log2['default'])(e); } throw e; } } return; }; /** * start media playback * * @return {player} * a reference to the player object this function was called on */ player.prototype.play = function play() { // only calls the tech's play if we already have a src loaded if (this.src() || this.currentsrc()) { this.techcall_('play'); } else { this.tech_.one('loadstart', function () { this.play(); }); } return this; }; /** * pause the video playback * * @return {player} * a reference to the player object this function was called on */ player.prototype.pause = function pause() { this.techcall_('pause'); return this; }; /** * check if the player is paused or has yet to play * * @return {boolean} * - false: if the media is currently playing * - true: if media is not currently playing */ player.prototype.paused = function paused() { // the initial state of paused should be true (in safari it's actually false) return this.techget_('paused') === false ? false : true; }; /** * returns whether or not the user is "scrubbing". scrubbing is * when the user has clicked the progress bar handle and is * dragging it along the progress bar. * * @param {boolean} [isscrubbing] * wether the user is or is not scrubbing * * @return {boolean|player} * a instance of the player that called this function when setting, * and the value of scrubbing when getting */ player.prototype.scrubbing = function scrubbing(isscrubbing) { if (isscrubbing !== undefined) { this.scrubbing_ = !!isscrubbing; if (isscrubbing) { this.addclass('vjs-scrubbing'); } else { this.removeclass('vjs-scrubbing'); } return this; } return this.scrubbing_; }; /** * get or set the current time (in seconds) * * @param {number|string} [seconds] * the time to seek to in seconds * * @return {player|number} * - the current time in seconds when getting * - a reference to the current player object when setting */ player.prototype.currenttime = function currenttime(seconds) { if (seconds !== undefined) { this.techcall_('setcurrenttime', seconds); return this; } // cache last currenttime and return. default to 0 seconds // // caching the currenttime is meant to prevent a massive amount of reads on the tech's // currenttime when scrubbing, but may not provide much performance benefit afterall. // should be tested. also something has to read the actual current time or the cache will // never get updated. this.cache_.currenttime = this.techget_('currenttime') || 0; return this.cache_.currenttime; }; /** * normally gets the length in time of the video in seconds; * in all but the rarest use cases an argument will not be passed to the method * * > **note**: the video must have started loading before the duration can be * known, and in the case of flash, may not be known until the video starts * playing. * * @fires player#durationchange * * @param {number} [seconds] * the duration of the video to set in seconds * * @return {number|player} * - the duration of the video in seconds when getting * - a reference to the player that called this function * when setting */ player.prototype.duration = function duration(seconds) { if (seconds === undefined) { return this.cache_.duration || 0; } seconds = parsefloat(seconds) || 0; // standardize on inifity for signaling video is live if (seconds < 0) { seconds = infinity; } if (seconds !== this.cache_.duration) { // cache the last set value for optimized scrubbing (esp. flash) this.cache_.duration = seconds; if (seconds === infinity) { this.addclass('vjs-live'); } else { this.removeclass('vjs-live'); } /** * @event player#durationchange * @type {eventtarget~event} */ this.trigger('durationchange'); } return this; }; /** * calculates how much time is left in the video. not part * of the native video api. * * @return {number} * the time remaining in seconds */ player.prototype.remainingtime = function remainingtime() { return this.duration() - this.currenttime(); }; // // kind of like an array of portions of the video that have been downloaded. /** * get a timerange object with an array of the times of the video * that have been downloaded. if you just want the percent of the * video that's been downloaded, use bufferedpercent. * * @see [buffered spec]{@link http://dev.w3.org/html5/spec/video.html#dom-media-buffered} * * @return {timerange} * a mock timerange object (following html spec) */ player.prototype.buffered = function buffered() { var buffered = this.techget_('buffered'); if (!buffered || !buffered.length) { buffered = (0, _timeranges.createtimerange)(0, 0); } return buffered; }; /** * get the percent (as a decimal) of the video that's been downloaded. * this method is not a part of the native html video api. * * @return {number} * a decimal between 0 and 1 representing the percent * that is bufferred 0 being 0% and 1 being 100% */ player.prototype.bufferedpercent = function bufferedpercent() { return (0, _buffer.bufferedpercent)(this.buffered(), this.duration()); }; /** * get the ending time of the last buffered time range * this is used in the progress bar to encapsulate all time ranges. * * @return {number} * the end of the last buffered time range */ player.prototype.bufferedend = function bufferedend() { var buffered = this.buffered(); var duration = this.duration(); var end = buffered.end(buffered.length - 1); if (end > duration) { end = duration; } return end; }; /** * get or set the current volume of the media * * @param {number} [percentasdecimal] * the new volume as a decimal percent: * - 0 is muted/0%/off * - 1.0 is 100%/full * - 0.5 is half volume or 50% * * @return {player|number} * a reference to the calling player when setting and the * current volume as a percent when getting */ player.prototype.volume = function volume(percentasdecimal) { var vol = void 0; if (percentasdecimal !== undefined) { // force value to between 0 and 1 vol = math.max(0, math.min(1, parsefloat(percentasdecimal))); this.cache_.volume = vol; this.techcall_('setvolume', vol); return this; } // default to 1 when returning current volume. vol = parsefloat(this.techget_('volume')); return isnan(vol) ? 1 : vol; }; /** * get the current muted state, or turn mute on or off * * @param {boolean} [muted] * - true to mute * - false to unmute * * @return {boolean|player} * - true if mute is on and getting * - false if mute is off and getting * - a reference to the current player when setting */ player.prototype.muted = function muted(_muted) { if (_muted !== undefined) { this.techcall_('setmuted', _muted); return this; } return this.techget_('muted') || false; }; /** * check if current tech can support native fullscreen * (e.g. with built in controls like ios, so not our flash swf) * * @return {boolean} * if native fullscreen is supported */ player.prototype.supportsfullscreen = function supportsfullscreen() { return this.techget_('supportsfullscreen') || false; }; /** * check if the player is in fullscreen mode or tell the player that it * is or is not in fullscreen mode. * * > note: as of the latest html5 spec, isfullscreen is no longer an official * property and instead document.fullscreenelement is used. but isfullscreen is * still a valuable property for internal player workings. * * @param {boolean} [isfs] * set the players current fullscreen state * * @return {boolean|player} * - true if fullscreen is on and getting * - false if fullscreen is off and getting * - a reference to the current player when setting */ player.prototype.isfullscreen = function isfullscreen(isfs) { if (isfs !== undefined) { this.isfullscreen_ = !!isfs; return this; } return !!this.isfullscreen_; }; /** * increase the size of the video to full screen * in some browsers, full screen is not supported natively, so it enters * "full window mode", where the video fills the browser window. * in browsers and devices that support native full screen, sometimes the * browser's default controls will be shown, and not the video.js custom skin. * this includes most mobile devices (ios, android) and older versions of * safari. * * @fires player#fullscreenchange * @return {player} * a reference to the current player */ player.prototype.requestfullscreen = function requestfullscreen() { var fsapi = _fullscreenapi2['default']; this.isfullscreen(true); if (fsapi.requestfullscreen) { // the browser supports going fullscreen at the element level so we can // take the controls fullscreen as well as the video // trigger fullscreenchange event after change // we have to specifically add this each time, and remove // when canceling fullscreen. otherwise if there's multiple // players on a page, they would all be reacting to the same fullscreen // events events.on(_document2['default'], fsapi.fullscreenchange, fn.bind(this, function documentfullscreenchange(e) { this.isfullscreen(_document2['default'][fsapi.fullscreenelement]); // if cancelling fullscreen, remove event listener. if (this.isfullscreen() === false) { events.off(_document2['default'], fsapi.fullscreenchange, documentfullscreenchange); } /** * @event player#fullscreenchange * @type {eventtarget~event} */ this.trigger('fullscreenchange'); })); this.el_[fsapi.requestfullscreen](); } else if (this.tech_.supportsfullscreen()) { // we can't take the video.js controls fullscreen but we can go fullscreen // with native controls this.techcall_('enterfullscreen'); } else { // fullscreen isn't supported so we'll just stretch the video element to // fill the viewport this.enterfullwindow(); /** * @event player#fullscreenchange * @type {eventtarget~event} */ this.trigger('fullscreenchange'); } return this; }; /** * return the video to its normal size after having been in full screen mode * * @fires player#fullscreenchange * * @return {player} * a reference to the current player */ player.prototype.exitfullscreen = function exitfullscreen() { var fsapi = _fullscreenapi2['default']; this.isfullscreen(false); // check for browser element fullscreen support if (fsapi.requestfullscreen) { _document2['default'][fsapi.exitfullscreen](); } else if (this.tech_.supportsfullscreen()) { this.techcall_('exitfullscreen'); } else { this.exitfullwindow(); /** * @event player#fullscreenchange * @type {eventtarget~event} */ this.trigger('fullscreenchange'); } return this; }; /** * when fullscreen isn't supported we can stretch the * video container to as wide as the browser will let us. * * @fires player#enterfullwindow */ player.prototype.enterfullwindow = function enterfullwindow() { this.isfullwindow = true; // storing original doc overflow value to return to when fullscreen is off this.docorigoverflow = _document2['default'].documentelement.style.overflow; // add listener for esc key to exit fullscreen events.on(_document2['default'], 'keydown', fn.bind(this, this.fullwindowonesckey)); // hide any scroll bars _document2['default'].documentelement.style.overflow = 'hidden'; // apply fullscreen styles dom.addelclass(_document2['default'].body, 'vjs-full-window'); /** * @event player#enterfullwindow * @type {eventtarget~event} */ this.trigger('enterfullwindow'); }; /** * check for call to either exit full window or * full screen on esc key * * @param {string} event * event to check for key press */ player.prototype.fullwindowonesckey = function fullwindowonesckey(event) { if (event.keycode === 27) { if (this.isfullscreen() === true) { this.exitfullscreen(); } else { this.exitfullwindow(); } } }; /** * exit full window * * @fires player#exitfullwindow */ player.prototype.exitfullwindow = function exitfullwindow() { this.isfullwindow = false; events.off(_document2['default'], 'keydown', this.fullwindowonesckey); // unhide scroll bars. _document2['default'].documentelement.style.overflow = this.docorigoverflow; // remove fullscreen styles dom.removeelclass(_document2['default'].body, 'vjs-full-window'); // resize the box, controller, and poster to original sizes // this.positionall(); /** * @event player#exitfullwindow * @type {eventtarget~event} */ this.trigger('exitfullwindow'); }; /** * check whether the player can play a given mimetype * * @see https://www.w3.org/tr/2011/wd-html5-20110113/video.html#dom-navigator-canplaytype * * @param {string} type * the mimetype to check * * @return {string} * 'probably', 'maybe', or '' (empty string) */ player.prototype.canplaytype = function canplaytype(type) { var can = void 0; // loop through each playback technology in the options order for (var i = 0, j = this.options_.techorder; i < j.length; i++) { var techname = (0, _totitlecase2['default'])(j[i]); var tech = _tech2['default'].gettech(techname); // support old behavior of techs being registered as components. // remove once that deprecated behavior is removed. if (!tech) { tech = _component2['default'].getcomponent(techname); } // check if the current tech is defined before continuing if (!tech) { _log2['default'].error('the "' + techname + '" tech is undefined. skipped browser support check for that tech.'); continue; } // check if the browser supports this technology if (tech.issupported()) { can = tech.canplaytype(type); if (can) { return can; } } } return ''; }; /** * select source based on tech-order or source-order * uses source-order selection if `options.sourceorder` is truthy. otherwise, * defaults to tech-order selection * * @param {array} sources * the sources for a media asset * * @return {object|boolean} * object of source and tech order or false */ player.prototype.selectsource = function selectsource(sources) { var _this4 = this; // get only the techs specified in `techorder` that exist and are supported by the // current platform var techs = this.options_.techorder.map(_totitlecase2['default']).map(function (techname) { // `component.getcomponent(...)` is for support of old behavior of techs // being registered as components. // remove once that deprecated behavior is removed. return [techname, _tech2['default'].gettech(techname) || _component2['default'].getcomponent(techname)]; }).filter(function (_ref) { var techname = _ref[0], tech = _ref[1]; // check if the current tech is defined before continuing if (tech) { // check if the browser supports this technology return tech.issupported(); } _log2['default'].error('the "' + techname + '" tech is undefined. skipped browser support check for that tech.'); return false; }); // iterate over each `innerarray` element once per `outerarray` element and execute // `tester` with both. if `tester` returns a non-falsy value, exit early and return // that value. var findfirstpassingtechsourcepair = function findfirstpassingtechsourcepair(outerarray, innerarray, tester) { var found = void 0; outerarray.some(function (outerchoice) { return innerarray.some(function (innerchoice) { found = tester(outerchoice, innerchoice); if (found) { return true; } }); }); return found; }; var foundsourceandtech = void 0; var flip = function flip(fn) { return function (a, b) { return fn(b, a); }; }; var finder = function finder(_ref2, source) { var techname = _ref2[0], tech = _ref2[1]; if (tech.canplaysource(source, _this4.options_[techname.tolowercase()])) { return { source: source, tech: techname }; } }; // depending on the truthiness of `options.sourceorder`, we swap the order of techs and sources // to select from them based on their priority. if (this.options_.sourceorder) { // source-first ordering foundsourceandtech = findfirstpassingtechsourcepair(sources, techs, flip(finder)); } else { // tech-first ordering foundsourceandtech = findfirstpassingtechsourcepair(techs, sources, finder); } return foundsourceandtech || false; }; /** * the source function updates the video source * there are three types of variables you can pass as the argument. * **url string**: a url to the the video file. use this method if you are sure * the current playback technology (html5/flash) can support the source you * provide. currently only mp4 files can be used in both html5 and flash. * * @param {tech~sourceobject|tech~sourceobject[]} [source] * one sourceobject or an array of sourceobjects * * @return {string|player} * - the current video source when getting * - the player when setting */ player.prototype.src = function src(source) { if (source === undefined) { return this.techget_('src'); } var currenttech = _tech2['default'].gettech(this.techname_); // support old behavior of techs being registered as components. // remove once that deprecated behavior is removed. if (!currenttech) { currenttech = _component2['default'].getcomponent(this.techname_); } // case: array of source objects to choose from and pick the best to play if (array.isarray(source)) { this.sourcelist_(source); // case: url string (http://myvideo...) } else if (typeof source === 'string') { // create a source object from the string this.src({ src: source }); // case: source object { src: '', type: '' ... } } else if (source instanceof object) { // check if the source has a type and the loaded tech cannot play the source // if there's no type we'll just try the current tech if (source.type && !currenttech.canplaysource(source, this.options_[this.techname_.tolowercase()])) { // create a source list with the current source and send through // the tech loop to check for a compatible technology this.sourcelist_([source]); } else { this.cache_.sources = null; this.cache_.source = source; this.cache_.src = source.src; this.currenttype_ = source.type || ''; // wait until the tech is ready to set the source this.ready(function () { // the setsource tech method was added with source handlers // so older techs won't support it // we need to check the direct prototype for the case where subclasses // of the tech do not support source handlers if (currenttech.prototype.hasownproperty('setsource')) { this.techcall_('setsource', source); } else { this.techcall_('src', source.src); } if (this.options_.preload === 'auto') { this.load(); } if (this.options_.autoplay) { this.play(); } // set the source synchronously if possible (#2326) }, true); } } return this; }; /** * handle an array of source objects * * @param {tech~sourceobject[]} sources * array of source objects * * @private */ player.prototype.sourcelist_ = function sourcelist_(sources) { var sourcetech = this.selectsource(sources); if (sourcetech) { if (sourcetech.tech === this.techname_) { // if this technology is already loaded, set the source this.src(sourcetech.source); } else { // load this technology with the chosen source this.loadtech_(sourcetech.tech, sourcetech.source); } this.cache_.sources = sources; } else { // we need to wrap this in a timeout to give folks a chance to add error event handlers this.settimeout(function () { this.error({ code: 4, message: this.localize(this.options_.notsupportedmessage) }); }, 0); // we could not find an appropriate tech, but let's still notify the delegate that this is it // this needs a better comment about why this is needed this.triggerready(); } }; /** * begin loading the src data. * * @return {player} * a reference to the player */ player.prototype.load = function load() { this.techcall_('load'); return this; }; /** * reset the player. loads the first tech in the techorder, * and calls `reset` on the tech`. * * @return {player} * a reference to the player */ player.prototype.reset = function reset() { this.loadtech_((0, _totitlecase2['default'])(this.options_.techorder[0]), null); this.techcall_('reset'); return this; }; /** * returns all of the current source objects. * * @return {tech~sourceobject[]} * the current source objects */ player.prototype.currentsources = function currentsources() { var source = this.currentsource(); var sources = []; // assume `{}` or `{ src }` if (object.keys(source).length !== 0) { sources.push(source); } return this.cache_.sources || sources; }; /** * returns the current source object. * * @return {tech~sourceobject} * the current source object */ player.prototype.currentsource = function currentsource() { var source = {}; var src = this.currentsrc(); if (src) { source.src = src; } return this.cache_.source || source; }; /** * returns the fully qualified url of the current source value e.g. http://mysite.com/video.mp4 * can be used in conjuction with `currenttype` to assist in rebuilding the current source object. * * @return {string} * the current source */ player.prototype.currentsrc = function currentsrc() { return this.techget_('currentsrc') || this.cache_.src || ''; }; /** * get the current source type e.g. video/mp4 * this can allow you rebuild the current source object so that you could load the same * source and tech later * * @return {string} * the source mime type */ player.prototype.currenttype = function currenttype() { return this.currenttype_ || ''; }; /** * get or set the preload attribute * * @param {boolean} [value] * - true means that we should preload * - false maens that we should not preload * * @return {string|player} * - the preload attribute value when getting * - the player when setting */ player.prototype.preload = function preload(value) { if (value !== undefined) { this.techcall_('setpreload', value); this.options_.preload = value; return this; } return this.techget_('preload'); }; /** * get or set the autoplay attribute. * * @param {boolean} [value] * - true means that we should autoplay * - false maens that we should not autoplay * * @return {string|player} * - the current value of autoplay * - the player when setting */ player.prototype.autoplay = function autoplay(value) { if (value !== undefined) { this.techcall_('setautoplay', value); this.options_.autoplay = value; return this; } return this.techget_('autoplay', value); }; /** * get or set the loop attribute on the video element. * * @param {boolean} [value] * - true means that we should loop the video * - false means that we should not loop the video * * @return {string|player} * - the current value of loop when getting * - the player when setting */ player.prototype.loop = function loop(value) { if (value !== undefined) { this.techcall_('setloop', value); this.options_.loop = value; return this; } return this.techget_('loop'); }; /** * get or set the poster image source url * * @fires player#posterchange * * @param {string} [src] * poster image source url * * @return {string|player} * - the current value of poster when getting * - the player when setting */ player.prototype.poster = function poster(src) { if (src === undefined) { return this.poster_; } // the correct way to remove a poster is to set as an empty string // other falsey values will throw errors if (!src) { src = ''; } // update the internal poster variable this.poster_ = src; // update the tech's poster this.techcall_('setposter', src); // alert components that the poster has been set /** * this event fires when the poster image is changed on the player. * * @event player#posterchange * @type {eventtarget~event} */ this.trigger('posterchange'); return this; }; /** * some techs (e.g. youtube) can provide a poster source in an * asynchronous way. we want the poster component to use this * poster source so that it covers up the tech's controls. * (youtube's play button). however we only want to use this * soruce if the player user hasn't set a poster through * the normal apis. * * @fires player#posterchange * @listens tech#posterchange * @private */ player.prototype.handletechposterchange_ = function handletechposterchange_() { if (!this.poster_ && this.tech_ && this.tech_.poster) { this.poster_ = this.tech_.poster() || ''; // let components know the poster has changed this.trigger('posterchange'); } }; /** * get or set whether or not the controls are showing. * * @fires player#controlsenabled * * @param {boolean} [bool] * - true to turn controls on * - false to turn controls off * * @return {boolean|player} * - the current value of controls when getting * - the player when setting */ player.prototype.controls = function controls(bool) { if (bool !== undefined) { bool = !!bool; // don't trigger a change event unless it actually changed if (this.controls_ !== bool) { this.controls_ = bool; if (this.usingnativecontrols()) { this.techcall_('setcontrols', bool); } if (bool) { this.removeclass('vjs-controls-disabled'); this.addclass('vjs-controls-enabled'); /** * @event player#controlsenabled * @type {eventtarget~event} */ this.trigger('controlsenabled'); if (!this.usingnativecontrols()) { this.addtechcontrolslisteners_(); } } else { this.removeclass('vjs-controls-enabled'); this.addclass('vjs-controls-disabled'); /** * @event player#controlsdisabled * @type {eventtarget~event} */ this.trigger('controlsdisabled'); if (!this.usingnativecontrols()) { this.removetechcontrolslisteners_(); } } } return this; } return !!this.controls_; }; /** * toggle native controls on/off. native controls are the controls built into * devices (e.g. default iphone controls), flash, or other techs * (e.g. vimeo controls) * **this should only be set by the current tech, because only the tech knows * if it can support native controls** * * @fires player#usingnativecontrols * @fires player#usingcustomcontrols * * @param {boolean} [bool] * - true to turn native controls on * - false to turn native controls off * * @return {boolean|player} * - the current value of native controls when getting * - the player when setting */ player.prototype.usingnativecontrols = function usingnativecontrols(bool) { if (bool !== undefined) { bool = !!bool; // don't trigger a change event unless it actually changed if (this.usingnativecontrols_ !== bool) { this.usingnativecontrols_ = bool; if (bool) { this.addclass('vjs-using-native-controls'); /** * player is using the native device controls * * @event player#usingnativecontrols * @type {eventtarget~event} */ this.trigger('usingnativecontrols'); } else { this.removeclass('vjs-using-native-controls'); /** * player is using the custom html controls * * @event player#usingcustomcontrols * @type {eventtarget~event} */ this.trigger('usingcustomcontrols'); } } return this; } return !!this.usingnativecontrols_; }; /** * set or get the current mediaerror * * @fires player#error * * @param {mediaerror|string|number} [err] * a mediaerror or a string/number to be turned * into a mediaerror * * @return {mediaerror|null|player} * - the current mediaerror when getting (or null) * - the player when setting */ player.prototype.error = function error(err) { if (err === undefined) { return this.error_ || null; } // restoring to default if (err === null) { this.error_ = err; this.removeclass('vjs-error'); if (this.errordisplay) { this.errordisplay.close(); } return this; } this.error_ = new _mediaerror2['default'](err); // add the vjs-error classname to the player this.addclass('vjs-error'); // log the name of the error type and any message // ie8 just logs "[object object]" if you just log the error object _log2['default'].error('(code:' + this.error_.code + ' ' + _mediaerror2['default'].errortypes[this.error_.code] + ')', this.error_.message, this.error_); /** * @event player#error * @type {eventtarget~event} */ this.trigger('error'); return this; }; /** * report user activity * * @param {object} event * event object */ player.prototype.reportuseractivity = function reportuseractivity(event) { this.useractivity_ = true; }; /** * get/set if user is active * * @fires player#useractive * @fires player#userinactive * * @param {boolean} [bool] * - true if the user is active * - false if the user is inactive * @return {boolean|player} * - the current value of useractive when getting * - the player when setting */ player.prototype.useractive = function useractive(bool) { if (bool !== undefined) { bool = !!bool; if (bool !== this.useractive_) { this.useractive_ = bool; if (bool) { // if the user was inactive and is now active we want to reset the // inactivity timer this.useractivity_ = true; this.removeclass('vjs-user-inactive'); this.addclass('vjs-user-active'); /** * @event player#useractive * @type {eventtarget~event} */ this.trigger('useractive'); } else { // we're switching the state to inactive manually, so erase any other // activity this.useractivity_ = false; // chrome/safari/ie have bugs where when you change the cursor it can // trigger a mousemove event. this causes an issue when you're hiding // the cursor when the user is inactive, and a mousemove signals user // activity. making it impossible to go into inactive mode. specifically // this happens in fullscreen when we really need to hide the cursor. // // when this gets resolved in all browsers it can be removed // https://code.google.com/p/chromium/issues/detail?id=103041 if (this.tech_) { this.tech_.one('mousemove', function (e) { e.stoppropagation(); e.preventdefault(); }); } this.removeclass('vjs-user-active'); this.addclass('vjs-user-inactive'); /** * @event player#userinactive * @type {eventtarget~event} */ this.trigger('userinactive'); } } return this; } return this.useractive_; }; /** * listen for user activity based on timeout value * * @private */ player.prototype.listenforuseractivity_ = function listenforuseractivity_() { var mouseinprogress = void 0; var lastmovex = void 0; var lastmovey = void 0; var handleactivity = fn.bind(this, this.reportuseractivity); var handlemousemove = function handlemousemove(e) { // #1068 - prevent mousemove spamming // chrome bug: https://code.google.com/p/chromium/issues/detail?id=366970 if (e.screenx !== lastmovex || e.screeny !== lastmovey) { lastmovex = e.screenx; lastmovey = e.screeny; handleactivity(); } }; var handlemousedown = function handlemousedown() { handleactivity(); // for as long as the they are touching the device or have their mouse down, // we consider them active even if they're not moving their finger or mouse. // so we want to continue to update that they are active this.clearinterval(mouseinprogress); // setting useractivity=true now and setting the interval to the same time // as the activitycheck interval (250) should ensure we never miss the // next activitycheck mouseinprogress = this.setinterval(handleactivity, 250); }; var handlemouseup = function handlemouseup(event) { handleactivity(); // stop the interval that maintains activity if the mouse/touch is down this.clearinterval(mouseinprogress); }; // any mouse movement will be considered user activity this.on('mousedown', handlemousedown); this.on('mousemove', handlemousemove); this.on('mouseup', handlemouseup); // listen for keyboard navigation // shouldn't need to use inprogress interval because of key repeat this.on('keydown', handleactivity); this.on('keyup', handleactivity); // run an interval every 250 milliseconds instead of stuffing everything into // the mousemove/touchmove function itself, to prevent performance degradation. // `this.reportuseractivity` simply sets this.useractivity_ to true, which // then gets picked up by this loop // http://ejohn.org/blog/learning-from-twitter/ var inactivitytimeout = void 0; this.setinterval(function () { // check to see if mouse/touch activity has happened if (this.useractivity_) { // reset the activity tracker this.useractivity_ = false; // if the user state was inactive, set the state to active this.useractive(true); // clear any existing inactivity timeout to start the timer over this.cleartimeout(inactivitytimeout); var timeout = this.options_.inactivitytimeout; if (timeout > 0) { // in milliseconds, if no more activity has occurred the // user will be considered inactive inactivitytimeout = this.settimeout(function () { // protect against the case where the inactivitytimeout can trigger just // before the next user activity is picked up by the activity check loop // causing a flicker if (!this.useractivity_) { this.useractive(false); } }, timeout); } } }, 250); }; /** * gets or sets the current playback rate. a playback rate of * 1.0 represents normal speed and 0.5 would indicate half-speed * playback, for instance. * * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-media-playbackrate * * @param {number} [rate] * new playback rate to set. * * @return {number|player} * - the current playback rate when getting or 1.0 * - the player when setting */ player.prototype.playbackrate = function playbackrate(rate) { if (rate !== undefined) { this.techcall_('setplaybackrate', rate); return this; } if (this.tech_ && this.tech_.featuresplaybackrate) { return this.techget_('playbackrate'); } return 1.0; }; /** * gets or sets the audio flag * * @param {boolean} bool * - true signals that this is an audio player * - false signals that this is not an audio player * * @return {player|boolean} * - the current value of isaudio when getting * - the player if setting */ player.prototype.isaudio = function isaudio(bool) { if (bool !== undefined) { this.isaudio_ = !!bool; return this; } return !!this.isaudio_; }; /** * get the {@link videotracklist} * * @see https://html.spec.whatwg.org/multipage/embedded-content.html#videotracklist * * @return {videotracklist} * the current video track list */ player.prototype.videotracks = function videotracks() { // if we have not yet loadtech_, we create videotracks_ // these will be passed to the tech during loading if (!this.tech_) { this.videotracks_ = this.videotracks_ || new _videotracklist2['default'](); return this.videotracks_; } return this.tech_.videotracks(); }; /** * get the {@link audiotracklist} * * @see https://html.spec.whatwg.org/multipage/embedded-content.html#audiotracklist * * @return {audiotracklist} * the current audio track list */ player.prototype.audiotracks = function audiotracks() { // if we have not yet loadtech_, we create videotracks_ // these will be passed to the tech during loading if (!this.tech_) { this.audiotracks_ = this.audiotracks_ || new _audiotracklist2['default'](); return this.audiotracks_; } return this.tech_.audiotracks(); }; /** * get the {@link texttracklist} * * text tracks are tracks of timed text events. * - captions: text displayed over the video * for the hearing impaired * - subtitles: text displayed over the video for * those who don't understand language in the video * - chapters: text displayed in a menu allowing the user to jump * to particular points (chapters) in the video * - descriptions: (not yet implemented) audio descriptions that are read back to * the user by a screen reading device * * @see http://www.w3.org/html/wg/drafts/html/master/embedded-content-0.html#dom-media-texttracks * * @return {texttracklist|undefined} * the current texttracklist or undefined if * or undefined if we don't have a tech */ player.prototype.texttracks = function texttracks() { // cannot use techget_ directly because it checks to see whether the tech is ready. // flash is unlikely to be ready in time but texttracks should still work. if (this.tech_) { return this.tech_.texttracks(); } }; /** * get the "remote" {@link texttracklist}. remote text tracks * are tracks that were added to the html video element and can * be removed, whereas normal texttracks cannot be removed. * * * @return {texttracklist|undefined} * the current remote text track list or undefined * if we don't have a tech */ player.prototype.remotetexttracks = function remotetexttracks() { if (this.tech_) { return this.tech_.remotetexttracks(); } }; /** * get the "remote" {@link htmltrackelementlist}. * this gives the user all of the dom elements that match up * with the remote {@link texttracklist}. * * @return {htmltrackelementlist} * the current remote text track list elements * or undefined if we don't have a tech */ player.prototype.remotetexttrackels = function remotetexttrackels() { if (this.tech_) { return this.tech_.remotetexttrackels(); } }; /** * a helper method for adding a {@link texttrack} to our * {@link texttracklist}. * * in addition to the w3c settings we allow adding additional info through options. * * @see http://www.w3.org/html/wg/drafts/html/master/embedded-content-0.html#dom-media-addtexttrack * * @param {string} [kind] * the kind of texttrack you are adding * * @param {string} [label] * the label to give the texttrack label * * @param {string} [language] * the language to set on the texttrack * * @return {texttrack|undefined} * the texttrack that was added or undefined * if there is no tech */ player.prototype.addtexttrack = function addtexttrack(kind, label, language) { if (this.tech_) { return this.tech_.addtexttrack(kind, label, language); } }; /** * create a remote {@link texttrack} and an {@link htmltrackelement}. it will * automatically removed from the video element whenever the source changes, unless * manualcleanup is set to false. * * @param {object} options * options to pass to {@link htmltrackelement} during creation. see * {@link htmltrackelement} for object properties that you should use. * * @param {boolean} [manualcleanup=true] if set to false, the texttrack will be * * @return {htmltrackelement} * the htmltrackelement that was created and added * to the htmltrackelementlist and the remote * texttracklist * * @deprecated the default value of the "manualcleanup" parameter will default * to "false" in upcoming versions of video.js */ player.prototype.addremotetexttrack = function addremotetexttrack(options, manualcleanup) { if (this.tech_) { return this.tech_.addremotetexttrack(options, manualcleanup); } }; /** * remove a remote {@link texttrack} from the respective * {@link texttracklist} and {@link htmltrackelementlist}. * * @param {object} track * remote {@link texttrack} to remove * * @return {undefined} * does not return anything */ player.prototype.removeremotetexttrack = function removeremotetexttrack() { var _ref3 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, _ref3$track = _ref3.track, track = _ref3$track === undefined ? arguments[0] : _ref3$track; // destructure the input into an object with a track argument, defaulting to arguments[0] // default the whole argument to an empty object if nothing was passed in if (this.tech_) { return this.tech_.removeremotetexttrack(track); } }; /** * get video width * * @return {number} * current video width */ player.prototype.videowidth = function videowidth() { return this.tech_ && this.tech_.videowidth && this.tech_.videowidth() || 0; }; /** * get video height * * @return {number} * current video height */ player.prototype.videoheight = function videoheight() { return this.tech_ && this.tech_.videoheight && this.tech_.videoheight() || 0; }; // methods to add support for // initialtime: function() { return this.techcall_('initialtime'); }, // startoffsettime: function() { return this.techcall_('startoffsettime'); }, // played: function() { return this.techcall_('played'); }, // defaultplaybackrate: function() { return this.techcall_('defaultplaybackrate'); }, // defaultmuted: function() { return this.techcall_('defaultmuted'); } /** * the player's language code * note: the language should be set in the player options if you want the * the controls to be built with a specific language. changing the lanugage * later will not update controls text. * * @param {string} [code] * the language code to set the player to * * @return {string|player} * - the current language code when getting * - a reference to the player when setting */ player.prototype.language = function language(code) { if (code === undefined) { return this.language_; } this.language_ = string(code).tolowercase(); return this; }; /** * get the player's language dictionary * merge every time, because a newly added plugin might call videojs.addlanguage() at any time * languages specified directly in the player options have precedence * * @return {array} * an array of of supported languages */ player.prototype.languages = function languages() { return (0, _mergeoptions2['default'])(player.prototype.options_.languages, this.languages_); }; /** * returns a javascript object reperesenting the current track * information. **does not return it as json** * * @return {object} * object representing the current of track info */ player.prototype.tojson = function tojson() { var options = (0, _mergeoptions2['default'])(this.options_); var tracks = options.tracks; options.tracks = []; for (var i = 0; i < tracks.length; i++) { var track = tracks[i]; // deep merge tracks and null out player so no circular references track = (0, _mergeoptions2['default'])(track); track.player = undefined; options.tracks[i] = track; } return options; }; /** * creates a simple modal dialog (an instance of the {@link modaldialog} * component) that immediately overlays the player with arbitrary * content and removes itself when closed. * * @param {string|function|element|array|null} content * same as {@link modaldialog#content}'s param of the same name. * the most straight-forward usage is to provide a string or dom * element. * * @param {object} [options] * extra options which will be passed on to the {@link modaldialog}. * * @return {modaldialog} * the {@link modaldialog} that was created */ player.prototype.createmodal = function createmodal(content, options) { var _this5 = this; options = options || {}; options.content = content || ''; var modal = new _modaldialog2['default'](this, options); this.addchild(modal); modal.on('dispose', function () { _this5.removechild(modal); }); return modal.open(); }; /** * gets tag settings * * @param {element} tag * the player tag * * @return {object} * an object containing all of the settings * for a player tag */ player.gettagsettings = function gettagsettings(tag) { var baseoptions = { sources: [], tracks: [] }; var tagoptions = dom.getelattributes(tag); var datasetup = tagoptions['data-setup']; if (dom.haselclass(tag, 'vjs-fluid')) { tagoptions.fluid = true; } // check if data-setup attr exists. if (datasetup !== null) { // parse options json // if empty string, make it a parsable json object. var _safeparsetuple = (0, _tuple2['default'])(datasetup || '{}'), err = _safeparsetuple[0], data = _safeparsetuple[1]; if (err) { _log2['default'].error(err); } (0, _obj.assign)(tagoptions, data); } (0, _obj.assign)(baseoptions, tagoptions); // get tag children settings if (tag.haschildnodes()) { var children = tag.childnodes; for (var i = 0, j = children.length; i < j; i++) { var child = children[i]; // change case needed: http://ejohn.org/blog/nodename-case-sensitivity/ var childname = child.nodename.tolowercase(); if (childname === 'source') { baseoptions.sources.push(dom.getelattributes(child)); } else if (childname === 'track') { baseoptions.tracks.push(dom.getelattributes(child)); } } } return baseoptions; }; /** * determine wether or not flexbox is supported * * @return {boolean} * - true if flexbox is supported * - false if flexbox is not supported */ player.prototype.flexnotsupported_ = function flexnotsupported_() { var elem = _document2['default'].createelement('i'); // note: we don't actually use flexbasis (or flexorder), but it's one of the more // common flex features that we can rely on when checking for flex support. return !('flexbasis' in elem.style || 'webkitflexbasis' in elem.style || 'mozflexbasis' in elem.style || 'msflexbasis' in elem.style || // ie10-specific (2012 flex spec) 'msflexorder' in elem.style); }; return player; }(_component2['default']); /** * global player list * * @type {object} */ player.players = {}; var navigator = _window2['default'].navigator; /* * player instance options, surfaced using options * options = player.prototype.options_ * make changes in options, not here. * * @type {object} * @private */ player.prototype.options_ = { // default order of fallback technology techorder: ['html5', 'flash'], // techorder: ['flash','html5'], html5: {}, flash: {}, // defaultvolume: 0.85, defaultvolume: 0.00, // default inactivity timeout inactivitytimeout: 2000, // default playback rates playbackrates: [], // add playback rate selection by adding rates // 'playbackrates': [0.5, 1, 1.5, 2], // included control sets children: ['medialoader', 'posterimage', 'texttrackdisplay', 'loadingspinner', 'bigplaybutton', 'controlbar', 'errordisplay', 'texttracksettings'], language: navigator && (navigator.languages && navigator.languages[0] || navigator.userlanguage || navigator.language) || 'en', // locales and their language translations languages: {}, // default message to show when a video cannot be played. notsupportedmessage: 'no compatible source was found for this media.' }; [ /** * returns whether or not the player is in the "ended" state. * * @return {boolean} true if the player is in the ended state, false if not. * @method player#ended */ 'ended', /** * returns whether or not the player is in the "seeking" state. * * @return {boolean} true if the player is in the seeking state, false if not. * @method player#seeking */ 'seeking', /** * returns the timeranges of the media that are currently available * for seeking to. * * @return {timeranges} the seekable intervals of the media timeline * @method player#seekable */ 'seekable', /** * returns the current state of network activity for the element, from * the codes in the list below. * - network_empty (numeric value 0) * the element has not yet been initialised. all attributes are in * their initial states. * - network_idle (numeric value 1) * the element's resource selection algorithm is active and has * selected a resource, but it is not actually using the network at * this time. * - network_loading (numeric value 2) * the user agent is actively trying to download data. * - network_no_source (numeric value 3) * the element's resource selection algorithm is active, but it has * not yet found a resource to use. * * @see https://html.spec.whatwg.org/multipage/embedded-content.html#network-states * @return {number} the current network activity state * @method player#networkstate */ 'networkstate', /** * returns a value that expresses the current state of the element * with respect to rendering the current playback position, from the * codes in the list below. * - have_nothing (numeric value 0) * no information regarding the media resource is available. * - have_metadata (numeric value 1) * enough of the resource has been obtained that the duration of the * resource is available. * - have_current_data (numeric value 2) * data for the immediate current playback position is available. * - have_future_data (numeric value 3) * data for the immediate current playback position is available, as * well as enough data for the user agent to advance the current * playback position in the direction of playback. * - have_enough_data (numeric value 4) * the user agent estimates that enough data is available for * playback to proceed uninterrupted. * * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-media-readystate * @return {number} the current playback rendering state * @method player#readystate */ 'readystate'].foreach(function (fn) { player.prototype[fn] = function () { return this.techget_(fn); }; }); tech_events_retrigger.foreach(function (event) { player.prototype['handletech' + (0, _totitlecase2['default'])(event) + '_'] = function () { return this.trigger(event); }; }); /** * fired when the player has initial duration and dimension information * * @event player#loadedmetadata * @type {eventtarget~event} */ /** * fired when the player has downloaded data at the current playback position * * @event player#loadeddata * @type {eventtarget~event} */ /** * fired when the current playback position has changed * * during playback this is fired every 15-250 milliseconds, depending on the * playback technology in use. * * @event player#timeupdate * @type {eventtarget~event} */ /** * fired when the volume changes * * @event player#volumechange * @type {eventtarget~event} */ _component2['default'].registercomponent('player', player); exports['default'] = player; },{"1":1,"4":4,"41":41,"44":44,"45":45,"46":46,"5":5,"50":50,"55":55,"59":59,"60":60,"61":61,"62":62,"63":63,"68":68,"69":69,"71":71,"76":76,"78":78,"79":79,"8":8,"81":81,"82":82,"83":83,"85":85,"86":86,"87":87,"88":88,"89":89,"90":90,"91":91,"94":94,"95":95,"97":97}],52:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _player = _dereq_(51); var _player2 = _interoprequiredefault(_player); function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } /** * the method for registering a video.js plugin. {@link videojs:videojs.registerplugin]. * * @param {string} name * the name of the plugin that is being registered * * @param {plugins:pluginfn} init * the function that gets run when a `player` initializes. */ var plugin = function plugin(name, init) { _player2['default'].prototype[name] = init; }; /** * @file plugins.js * @module plugins */ exports['default'] = plugin; },{"51":51}],53:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _clickablecomponent = _dereq_(3); var _clickablecomponent2 = _interoprequiredefault(_clickablecomponent); var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file popup-button.js */ /** * a button class for use with {@link popup} controls * * @extends clickablecomponent */ var popupbutton = function (_clickablecomponent) { _inherits(popupbutton, _clickablecomponent); /** * create an instance of this class. * * @param {player} player * the `player` that this class should be attached to. * * @param {object} [options] * the key/value store of player options. */ function popupbutton(player) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; _classcallcheck(this, popupbutton); var _this = _possibleconstructorreturn(this, _clickablecomponent.call(this, player, options)); _this.update(); return _this; } /** * update the `popup` that this button is attached to. */ popupbutton.prototype.update = function update() { var popup = this.createpopup(); if (this.popup) { this.removechild(this.popup); } this.popup = popup; this.addchild(popup); if (this.items && this.items.length === 0) { this.hide(); } else if (this.items && this.items.length > 1) { this.show(); } }; /** * create a `popup`. - override with specific functionality for component * * @abstract */ popupbutton.prototype.createpopup = function createpopup() {}; /** * create the `popupbutton`s dom element. * * @return {element} * the element that gets created. */ popupbutton.prototype.createel = function createel() { return _clickablecomponent.prototype.createel.call(this, 'div', { classname: this.buildcssclass() }); }; /** * builds the default dom `classname`. * * @return {string} * the dom `classname` for this object. */ popupbutton.prototype.buildcssclass = function buildcssclass() { var menubuttonclass = 'vjs-menu-button'; // if the inline option is passed, we want to use different styles altogether. if (this.options_.inline === true) { menubuttonclass += '-inline'; } else { menubuttonclass += '-popup'; } return 'vjs-menu-button ' + menubuttonclass + ' ' + _clickablecomponent.prototype.buildcssclass.call(this); }; return popupbutton; }(_clickablecomponent2['default']); _component2['default'].registercomponent('popupbutton', popupbutton); exports['default'] = popupbutton; },{"3":3,"5":5}],54:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); var _dom = _dereq_(81); var dom = _interoprequirewildcard(_dom); var _fn = _dereq_(83); var fn = _interoprequirewildcard(_fn); var _events = _dereq_(82); var events = _interoprequirewildcard(_events); function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file popup.js */ /** * the popup component is used to build pop up controls. * * @extends component */ var popup = function (_component) { _inherits(popup, _component); function popup() { _classcallcheck(this, popup); return _possibleconstructorreturn(this, _component.apply(this, arguments)); } /** * add a popup item to the popup * * @param {object|string} component * component or component type to add * */ popup.prototype.additem = function additem(component) { this.addchild(component); component.on('click', fn.bind(this, function () { this.unlockshowing(); })); }; /** * create the `popupbutton`s dom element. * * @return {element} * the element that gets created. */ popup.prototype.createel = function createel() { var contenteltype = this.options_.contenteltype || 'ul'; this.contentel_ = dom.createel(contenteltype, { classname: 'vjs-menu-content' }); var el = _component.prototype.createel.call(this, 'div', { append: this.contentel_, classname: 'vjs-menu' }); el.appendchild(this.contentel_); // prevent clicks from bubbling up. needed for popup buttons, // where a click on the parent is significant events.on(el, 'click', function (event) { event.preventdefault(); event.stopimmediatepropagation(); }); return el; }; return popup; }(_component2['default']); _component2['default'].registercomponent('popup', popup); exports['default'] = popup; },{"5":5,"81":81,"82":82,"83":83}],55:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _clickablecomponent = _dereq_(3); var _clickablecomponent2 = _interoprequiredefault(_clickablecomponent); var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); var _fn = _dereq_(83); var fn = _interoprequirewildcard(_fn); var _dom = _dereq_(81); var dom = _interoprequirewildcard(_dom); var _browser = _dereq_(78); var browser = _interoprequirewildcard(_browser); function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file poster-image.js */ /** * a `clickablecomponent` that handles showing the poster image for the player. * * @extends clickablecomponent */ var posterimage = function (_clickablecomponent) { _inherits(posterimage, _clickablecomponent); /** * create an instance of this class. * * @param {player} player * the `player` that this class should attach to. * * @param {object} [options] * the key/value store of player options. */ function posterimage(player, options) { _classcallcheck(this, posterimage); var _this = _possibleconstructorreturn(this, _clickablecomponent.call(this, player, options)); _this.update(); player.on('posterchange', fn.bind(_this, _this.update)); return _this; } /** * clean up and dispose of the `posterimage`. */ posterimage.prototype.dispose = function dispose() { this.player().off('posterchange', this.update); _clickablecomponent.prototype.dispose.call(this); }; /** * create the `posterimage`s dom element. * * @return {element} * the element that gets created. */ posterimage.prototype.createel = function createel() { var el = dom.createel('div', { classname: 'vjs-poster', // don't want poster to be tabbable. tabindex: -1 }); // to ensure the poster image resizes while maintaining its original aspect // ratio, use a div with `background-size` when available. for browsers that // do not support `background-size` (e.g. ie8), fall back on using a regular // img element. if (!browser.background_size_supported) { this.fallbackimg_ = dom.createel('img'); el.appendchild(this.fallbackimg_); } return el; }; /** * an {@link eventtarget~eventlistener} for {@link player#posterchange} events. * * @listens player#posterchange * * @param {eventtarget~event} [event] * the `player#posterchange` event that triggered this function. */ posterimage.prototype.update = function update(event) { var url = this.player().poster(); this.setsrc(url); // if there's no poster source we should display:none on this component // so it's not still clickable or right-clickable if (url) { this.show(); } else { this.hide(); } }; /** * set the source of the `posterimage` depending on the display method. * * @param {string} url * the url to the source for the `posterimage`. */ posterimage.prototype.setsrc = function setsrc(url) { if (this.fallbackimg_) { this.fallbackimg_.src = url; } else { var backgroundimage = ''; // any falsey values should stay as an empty string, otherwise // this will throw an extra error if (url) { backgroundimage = 'url("' + url + '")'; } this.el_.style.backgroundimage = backgroundimage; } }; /** * an {@link eventtarget~eventlistener} for clicks on the `posterimage`. see * {@link clickablecomponent#handleclick} for instances where this will be triggered. * * @listens tap * @listens click * @listens keydown * * @param {eventtarget~event} event + the `click`, `tap` or `keydown` event that caused this function to be called. */ posterimage.prototype.handleclick = function handleclick(event) { // we don't want a click to trigger playback when controls are disabled if (!this.player_.controls()) { return; } if (this.player_.paused()) { this.player_.play(); } else { this.player_.pause(); } }; return posterimage; }(_clickablecomponent2['default']); _component2['default'].registercomponent('posterimage', posterimage); exports['default'] = posterimage; },{"3":3,"5":5,"78":78,"81":81,"83":83}],56:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; exports.hasloaded = exports.autosetuptimeout = exports.autosetup = undefined; var _dom = _dereq_(81); var dom = _interoprequirewildcard(_dom); var _events = _dereq_(82); var events = _interoprequirewildcard(_events); var _document = _dereq_(94); var _document2 = _interoprequiredefault(_document); var _window = _dereq_(95); var _window2 = _interoprequiredefault(_window); function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } /** * @file setup.js - functions for setting up a player without * user interaction based on the data-setup `attribute` of the video tag. * * @module setup */ var _windowloaded = false; var videojs = void 0; /** * set up any tags that have a data-setup `attribute` when the player is started. */ var autosetup = function autosetup() { // protect against breakage in non-browser environments. if (!dom.isreal()) { return; } // one day, when we stop supporting ie8, go back to this, but in the meantime...*hack hack hack* // var vids = array.prototype.slice.call(document.getelementsbytagname('video')); // var audios = array.prototype.slice.call(document.getelementsbytagname('audio')); // var mediaels = vids.concat(audios); // because ie8 doesn't support calling slice on a node list, we need to loop // through each list of elements to build up a new, combined list of elements. var vids = _document2['default'].getelementsbytagname('video'); var audios = _document2['default'].getelementsbytagname('audio'); var mediaels = []; if (vids && vids.length > 0) { for (var i = 0, e = vids.length; i < e; i++) { mediaels.push(vids[i]); } } if (audios && audios.length > 0) { for (var _i = 0, _e = audios.length; _i < _e; _i++) { mediaels.push(audios[_i]); } } // check if any media elements exist if (mediaels && mediaels.length > 0) { for (var _i2 = 0, _e2 = mediaels.length; _i2 < _e2; _i2++) { var mediael = mediaels[_i2]; // check if element exists, has getattribute func. // ie seems to consider typeof el.getattribute == 'object' instead of // 'function' like expected, at least when loading the player immediately. if (mediael && mediael.getattribute) { // make sure this player hasn't already been set up. if (mediael.player === undefined) { var options = mediael.getattribute('data-setup'); // check if data-setup attr exists. // we only auto-setup if they've added the data-setup attr. if (options !== null) { // create new video.js instance. videojs(mediael); } } // if getattribute isn't defined, we need to wait for the dom. } else { autosetuptimeout(1); break; } } // no videos were found, so keep looping unless page is finished loading. } else if (!_windowloaded) { autosetuptimeout(1); } }; /** * wait until the page is loaded before running autosetup. this will be called in * autosetup if `hasloaded` returns false. * * @param {number} wait * how long to wait in ms * * @param {videojs} [vjs] * the videojs library function */ function autosetuptimeout(wait, vjs) { if (vjs) { videojs = vjs; } _window2['default'].settimeout(autosetup, wait); } if (dom.isreal() && _document2['default'].readystate === 'complete') { _windowloaded = true; } else { /** * listen for the load event on window, and set _windowloaded to true. * * @listens load */ events.one(_window2['default'], 'load', function () { _windowloaded = true; }); } /** * check if the document has been loaded */ var hasloaded = function hasloaded() { return _windowloaded; }; exports.autosetup = autosetup; exports.autosetuptimeout = autosetuptimeout; exports.hasloaded = hasloaded; },{"81":81,"82":82,"94":94,"95":95}],57:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); var _dom = _dereq_(81); var dom = _interoprequirewildcard(_dom); var _obj = _dereq_(88); function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file slider.js */ /** * the base functionality for a slider. can be vertical or horizontal. * for instance the volume bar or the seek bar on a video is a slider. * * @extends component */ var slider = function (_component) { _inherits(slider, _component); /** * create an instance of this class * * @param {player} player * the `player` that this class should be attached to. * * @param {object} [options] * the key/value store of player options. */ function slider(player, options) { _classcallcheck(this, slider); // set property names to bar to match with the child slider class is looking for var _this = _possibleconstructorreturn(this, _component.call(this, player, options)); _this.bar = _this.getchild(_this.options_.barname); // set a horizontal or vertical class on the slider depending on the slider type _this.vertical(!!_this.options_.vertical); _this.on('mousedown', _this.handlemousedown); _this.on('touchstart', _this.handlemousedown); _this.on('focus', _this.handlefocus); _this.on('blur', _this.handleblur); _this.on('click', _this.handleclick); _this.on(player, 'controlsvisible', _this.update); _this.on(player, _this.playerevent, _this.update); return _this; } /** * create the `button`s dom element. * * @param {string} type * type of element to create. * * @param {object} [props={}] * list of properties in object form. * * @param {object} [attributes={}] * list of attributes in object form. * * @return {element} * the element that gets created. */ slider.prototype.createel = function createel(type) { var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var attributes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; // add the slider element class to all sub classes props.classname = props.classname + ' vjs-slider'; props = (0, _obj.assign)({ tabindex: 0 }, props); attributes = (0, _obj.assign)({ 'role': 'slider', 'aria-valuenow': 0, 'aria-valuemin': 0, 'aria-valuemax': 100, 'tabindex': 0 }, attributes); return _component.prototype.createel.call(this, type, props, attributes); }; /** * handle `mousedown` or `touchstart` events on the `slider`. * * @param {eventtarget~event} event * `mousedown` or `touchstart` event that triggered this function * * @listens mousedown * @listens touchstart * @fires slider#slideractive */ slider.prototype.handlemousedown = function handlemousedown(event) { var doc = this.bar.el_.ownerdocument; event.preventdefault(); dom.blocktextselection(); this.addclass('vjs-sliding'); /** * triggered when the slider is in an active state * * @event slider#slideractive * @type {eventtarget~event} */ this.trigger('slideractive'); this.on(doc, 'mousemove', this.handlemousemove); this.on(doc, 'mouseup', this.handlemouseup); this.on(doc, 'touchmove', this.handlemousemove); this.on(doc, 'touchend', this.handlemouseup); this.handlemousemove(event); }; /** * handle the `mousemove`, `touchmove`, and `mousedown` events on this `slider`. * the `mousemove` and `touchmove` events will only only trigger this function during * `mousedown` and `touchstart`. this is due to {@link slider#handlemousedown} and * {@link slider#handlemouseup}. * * @param {eventtarget~event} event * `mousedown`, `mousemove`, `touchstart`, or `touchmove` event that triggered * this function * * @listens mousemove * @listens touchmove */ slider.prototype.handlemousemove = function handlemousemove(event) {}; /** * handle `mouseup` or `touchend` events on the `slider`. * * @param {eventtarget~event} event * `mouseup` or `touchend` event that triggered this function. * * @listens touchend * @listens mouseup * @fires slider#sliderinactive */ slider.prototype.handlemouseup = function handlemouseup() { var doc = this.bar.el_.ownerdocument; dom.unblocktextselection(); this.removeclass('vjs-sliding'); /** * triggered when the slider is no longer in an active state. * * @event slider#sliderinactive * @type {eventtarget~event} */ this.trigger('sliderinactive'); this.off(doc, 'mousemove', this.handlemousemove); this.off(doc, 'mouseup', this.handlemouseup); this.off(doc, 'touchmove', this.handlemousemove); this.off(doc, 'touchend', this.handlemouseup); this.update(); }; /** * update the progress bar of the `slider`. */ slider.prototype.update = function update() { // in volumebar init we have a settimeout for update that pops and update to the end of the // execution stack. the player is destroyed before then update will cause an error if (!this.el_) { return; } // if scrubbing, we could use a cached value to make the handle keep up with the user's mouse. // on html5 browsers scrubbing is really smooth, but some flash players are slow, so we might want to utilize this later. // var progress = (this.player_.scrubbing()) ? this.player_.getcache().currenttime / this.player_.duration() : this.player_.currenttime() / this.player_.duration(); var progress = this.getpercent(); var bar = this.bar; // if there's no bar... if (!bar) { return; } // protect against no duration and other division issues if (typeof progress !== 'number' || progress !== progress || progress < 0 || progress === infinity) { progress = 0; } // convert to a percentage for setting var percentage = (progress * 100).tofixed(2) + '%'; // set the new bar width or height if (this.vertical()) { bar.el().style.height = percentage; } else { bar.el().style.width = percentage; } }; /** * calculate distance for slider * * @param {eventtarget~event} event * the event that caused this function to run. * * @return {number} * the current position of the slider. * - postition.x for vertical `slider`s * - postition.y for horizontal `slider`s */ slider.prototype.calculatedistance = function calculatedistance(event) { var position = dom.getpointerposition(this.el_, event); if (this.vertical()) { return position.y; } return position.x; }; /** * handle a `focus` event on this `slider`. * * @param {eventtarget~event} event * the `focus` event that caused this function to run. * * @listens focus */ slider.prototype.handlefocus = function handlefocus() { this.on(this.bar.el_.ownerdocument, 'keydown', this.handlekeypress); }; /** * handle a `keydown` event on the `slider`. watches for left, rigth, up, and down * arrow keys. this function will only be called when the slider has focus. see * {@link slider#handlefocus} and {@link slider#handleblur}. * * @param {eventtarget~event} event * the `keydown` event that caused this function to run. * * @listens keydown */ slider.prototype.handlekeypress = function handlekeypress(event) { // left and down arrows if (event.which === 37 || event.which === 40) { event.preventdefault(); this.stepback(); // up and right arrows } else if (event.which === 38 || event.which === 39) { event.preventdefault(); this.stepforward(); } }; /** * handle a `blur` event on this `slider`. * * @param {eventtarget~event} event * the `blur` event that caused this function to run. * * @listens blur */ slider.prototype.handleblur = function handleblur() { this.off(this.bar.el_.ownerdocument, 'keydown', this.handlekeypress); }; /** * listener for click events on slider, used to prevent clicks * from bubbling up to parent elements like button menus. * * @param {object} event * event that caused this object to run */ slider.prototype.handleclick = function handleclick(event) { event.stopimmediatepropagation(); event.preventdefault(); }; /** * get/set if slider is horizontal for vertical * * @param {boolean} [bool] * - true if slider is vertical, * - false is horizontal * * @return {boolean|slider} * - true if slider is vertical, and getting * - false is horizontal, and getting * - a reference to this object when setting */ slider.prototype.vertical = function vertical(bool) { if (bool === undefined) { return this.vertical_ || false; } this.vertical_ = !!bool; if (this.vertical_) { this.addclass('vjs-slider-vertical'); } else { this.addclass('vjs-slider-horizontal'); } return this; }; return slider; }(_component2['default']); _component2['default'].registercomponent('slider', slider); exports['default'] = slider; },{"5":5,"81":81,"88":88}],58:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; /** * @file flash-rtmp.js * @module flash-rtmp */ /** * add rtmp properties to the {@link flash} tech. * * @param {flash} flash * the flash tech class. * * @mixin flashrtmpdecorator */ function flashrtmpdecorator(flash) { flash.streamingformats = { 'rtmp/mp4': 'mp4', 'rtmp/flv': 'flv' }; /** * join connection and stream with an ampersand. * * @param {string} connection * the connection string. * * @param {string} stream * the stream string. */ flash.streamfromparts = function (connection, stream) { return connection + '&' + stream; }; /** * the flash parts object that contains connection and stream info. * * @typedef {object} flash~partsobject * * @property {string} connection * the connection string of a source, defaults to an empty string. * * @property {string} stream * the stream string of the source, defaults to an empty string. */ /** * convert a source url into a stream and connection parts. * * @param {string} src * the source url * * @return {flash~partsobject} * the parts object that contains a connection and a stream */ flash.streamtoparts = function (src) { var parts = { connection: '', stream: '' }; if (!src) { return parts; } // look for the normal url separator we expect, '&'. // if found, we split the url into two pieces around the // first '&'. var connend = src.search(/&(?!\w+=)/); var streambegin = void 0; if (connend !== -1) { streambegin = connend + 1; } else { // if there's not a '&', we use the last '/' as the delimiter. connend = streambegin = src.lastindexof('/') + 1; if (connend === 0) { // really, there's not a '/'? connend = streambegin = src.length; } } parts.connection = src.substring(0, connend); parts.stream = src.substring(streambegin, src.length); return parts; }; /** * check if the source type is a streaming type. * * @param {string} srctype * the mime type to check. * * @return {boolean} * - true if the source type is a streaming type. * - false if the source type is not a streaming type. */ flash.isstreamingtype = function (srctype) { return srctype in flash.streamingformats; }; // rtmp has four variations, any string starting // with one of these protocols should be valid /** * regular expression used to check if the source is an rtmp source. * * @property {regexp} flash.rtmp_re */ flash.rtmp_re = /^rtmp[set]?:\/\//i; /** * check if the source itself is a streaming type. * * @param {string} src * the url to the source. * * @return {boolean} * - true if the source url indicates that the source is streaming. * - false if the shource url indicates that the source url is not streaming. */ flash.isstreamingsrc = function (src) { return flash.rtmp_re.test(src); }; /** * a source handler for rtmp urls * @type {object} */ flash.rtmpsourcehandler = {}; /** * check if flash can play the given mime type. * * @param {string} type * the mime type to check * * @return {string} * 'maybe', or '' (empty string) */ flash.rtmpsourcehandler.canplaytype = function (type) { if (flash.isstreamingtype(type)) { return 'maybe'; } return ''; }; /** * check if flash can handle the source natively * * @param {object} source * the source object * * @param {object} [options] * the options passed to the tech * * @return {string} * 'maybe', or '' (empty string) */ flash.rtmpsourcehandler.canhandlesource = function (source, options) { var can = flash.rtmpsourcehandler.canplaytype(source.type); if (can) { return can; } if (flash.isstreamingsrc(source.src)) { return 'maybe'; } return ''; }; /** * pass the source to the flash object. * * @param {object} source * the source object * * @param {flash} tech * the instance of the flash tech * * @param {object} [options] * the options to pass to the source */ flash.rtmpsourcehandler.handlesource = function (source, tech, options) { var srcparts = flash.streamtoparts(source.src); tech.setrtmpconnection(srcparts.connection); tech.setrtmpstream(srcparts.stream); }; // register the native source handler flash.registersourcehandler(flash.rtmpsourcehandler); return flash; } exports['default'] = flashrtmpdecorator; },{}],59:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _tech = _dereq_(62); var _tech2 = _interoprequiredefault(_tech); var _dom = _dereq_(81); var dom = _interoprequirewildcard(_dom); var _url = _dereq_(92); var url = _interoprequirewildcard(_url); var _timeranges = _dereq_(90); var _flashrtmp = _dereq_(58); var _flashrtmp2 = _interoprequiredefault(_flashrtmp); var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); var _window = _dereq_(95); var _window2 = _interoprequiredefault(_window); var _obj = _dereq_(88); function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file flash.js * videojs-swf - custom flash player with html5-ish api * https://github.com/zencoder/video-js-swf * not using setuptriggers. using global onevent func to distribute events */ var navigator = _window2['default'].navigator; /** * flash media controller - wrapper for flash media api * * @mixes flashrtmpdecorator * @mixes tech~soucehandleradditions * @extends tech */ var flash = function (_tech) { _inherits(flash, _tech); /** * create an instance of this tech. * * @param {object} [options] * the key/value store of player options. * * @param {component~readycallback} ready * callback function to call when the `flash` tech is ready. */ function flash(options, ready) { _classcallcheck(this, flash); // set the source when ready var _this = _possibleconstructorreturn(this, _tech.call(this, options, ready)); if (options.source) { _this.ready(function () { this.setsource(options.source); }, true); } // having issues with flash reloading on certain page actions (hide/resize/fullscreen) in certain browsers // this allows resetting the playhead when we catch the reload if (options.starttime) { _this.ready(function () { this.load(); this.play(); this.currenttime(options.starttime); }, true); } // add global window functions that the swf expects // a 4.x workflow we weren't able to solve for in 5.0 // because of the need to hard code these functions // into the swf for security reasons _window2['default'].videojs = _window2['default'].videojs || {}; _window2['default'].videojs.flash = _window2['default'].videojs.flash || {}; _window2['default'].videojs.flash.onready = flash.onready; _window2['default'].videojs.flash.onevent = flash.onevent; _window2['default'].videojs.flash.onerror = flash.onerror; _this.on('seeked', function () { this.lastseektarget_ = undefined; }); return _this; } /** * create the `flash` tech's dom element. * * @return {element} * the element that gets created. */ flash.prototype.createel = function createel() { var options = this.options_; // if video.js is hosted locally you should also set the location // for the hosted swf, which should be relative to the page (not video.js) // otherwise this adds a cdn url. // the cdn also auto-adds a swf url for that specific version. if (!options.swf) { var ver = '5.3.0'; options.swf = '//vjs.zencdn.net/swf/' + ver + '/video-js.swf'; } // generate id for swf object var objid = options.techid; // merge default flashvars with ones passed in to init var flashvars = (0, _obj.assign)({ // swf callback functions readyfunction: 'videojs.flash.onready', eventproxyfunction: 'videojs.flash.onevent', erroreventproxyfunction: 'videojs.flash.onerror', // player settings autoplay: options.autoplay, preload: options.preload, loop: options.loop, muted: options.muted }, options.flashvars); // merge default parames with ones passed in var params = (0, _obj.assign)({ // opaque is needed to overlay controls, but can affect playback performance wmode: 'opaque', // using bgcolor prevents a white flash when the object is loading bgcolor: '#000000' }, options.params); // merge default attributes with ones passed in var attributes = (0, _obj.assign)({ // both id and name needed or swf to identify itself id: objid, name: objid, 'class': 'vjs-tech' }, options.attributes); this.el_ = flash.embed(options.swf, flashvars, params, attributes); this.el_.tech = this; return this.el_; }; /** * called by {@link player#play} to play using the `flash` `tech`. */ flash.prototype.play = function play() { if (this.ended()) { this.setcurrenttime(0); } this.el_.vjs_play(); }; /** * called by {@link player#pause} to pause using the `flash` `tech`. */ flash.prototype.pause = function pause() { this.el_.vjs_pause(); }; /** * a getter/setter for the `flash` tech's source object. * > note: please use {@link flash#setsource} * * @param {tech~sourceobject} [src] * the source object you want to set on the `flash` techs. * * @return {tech~sourceobject|undefined} * - the current source object when a source is not passed in. * - undefined when setting * * @deprecated since version 5. */ flash.prototype.src = function src(_src) { if (_src === undefined) { return this.currentsrc(); } // setting src through `src` not `setsrc` will be deprecated return this.setsrc(_src); }; /** * a getter/setter for the `flash` tech's source object. * * @param {tech~sourceobject} [src] * the source object you want to set on the `flash` techs. * * @return {tech~sourceobject|undefined} * - the current source object when a source is not passed in. * - undefined when setting */ flash.prototype.setsrc = function setsrc(src) { var _this2 = this; // make sure source url is absolute. src = url.getabsoluteurl(src); this.el_.vjs_src(src); // currently the swf doesn't autoplay if you load a source later. // e.g. load player w/ no source, wait 2s, set src. if (this.autoplay()) { this.settimeout(function () { return _this2.play(); }, 0); } }; /** * indicates whether the media is currently seeking to a new position or not. * * @return {boolean} * - true if seeking to a new position * - false otherwise */ flash.prototype.seeking = function seeking() { return this.lastseektarget_ !== undefined; }; /** * returns the current time in seconds that the media is at in playback. * * @param {number} time * current playtime of the media in seconds. */ flash.prototype.setcurrenttime = function setcurrenttime(time) { var seekable = this.seekable(); if (seekable.length) { // clamp to the current seekable range time = time > seekable.start(0) ? time : seekable.start(0); time = time < seekable.end(seekable.length - 1) ? time : seekable.end(seekable.length - 1); this.lastseektarget_ = time; this.trigger('seeking'); this.el_.vjs_setproperty('currenttime', time); _tech.prototype.setcurrenttime.call(this); } }; /** * get the current playback time in seconds * * @return {number} * the current time of playback in seconds. */ flash.prototype.currenttime = function currenttime() { // when seeking make the reported time keep up with the requested time // by reading the time we're seeking to if (this.seeking()) { return this.lastseektarget_ || 0; } return this.el_.vjs_getproperty('currenttime'); }; /** * get the current source * * @method currentsrc * @return {tech~sourceobject} * the current source */ flash.prototype.currentsrc = function currentsrc() { if (this.currentsource_) { return this.currentsource_.src; } return this.el_.vjs_getproperty('currentsrc'); }; /** * get the total duration of the current media. * * @return {number} 8 the total duration of the current media. */ flash.prototype.duration = function duration() { if (this.readystate() === 0) { return nan; } var duration = this.el_.vjs_getproperty('duration'); return duration >= 0 ? duration : infinity; }; /** * load media into tech. */ flash.prototype.load = function load() { this.el_.vjs_load(); }; /** * get the poster image that was set on the tech. */ flash.prototype.poster = function poster() { this.el_.vjs_getproperty('poster'); }; /** * poster images are not handled by the flash tech so make this is a no-op. */ flash.prototype.setposter = function setposter() {}; /** * determine the time ranges that can be seeked to in the media. * * @return {timerange} * returns the time ranges that can be seeked to. */ flash.prototype.seekable = function seekable() { var duration = this.duration(); if (duration === 0) { return (0, _timeranges.createtimerange)(); } return (0, _timeranges.createtimerange)(0, duration); }; /** * get and create a `timerange` object for buffering. * * @return {timerange} * the time range object that was created. */ flash.prototype.buffered = function buffered() { var ranges = this.el_.vjs_getproperty('buffered'); if (ranges.length === 0) { return (0, _timeranges.createtimerange)(); } return (0, _timeranges.createtimerange)(ranges[0][0], ranges[0][1]); }; /** * get fullscreen support - * * flash does not allow fullscreen through javascript * so this always returns false. * * @return {boolean} * the flash tech does not support fullscreen, so it will always return false. */ flash.prototype.supportsfullscreen = function supportsfullscreen() { // flash does not allow fullscreen through javascript return false; }; /** * flash does not allow fullscreen through javascript * so this always returns false. * * @return {boolean} * the flash tech does not support fullscreen, so it will always return false. */ flash.prototype.enterfullscreen = function enterfullscreen() { return false; }; return flash; }(_tech2['default']); // create setters and getters for attributes var _api = flash.prototype; var _readwrite = 'rtmpconnection,rtmpstream,preload,defaultplaybackrate,playbackrate,autoplay,loop,mediagroup,controller,controls,volume,muted,defaultmuted'.split(','); var _readonly = 'networkstate,readystate,initialtime,startoffsettime,paused,ended,videowidth,videoheight'.split(','); function _createsetter(attr) { var attrupper = attr.charat(0).touppercase() + attr.slice(1); _api['set' + attrupper] = function (val) { return this.el_.vjs_setproperty(attr, val); }; } function _creategetter(attr) { _api[attr] = function () { return this.el_.vjs_getproperty(attr); }; } // create getter and setters for all read/write attributes for (var i = 0; i < _readwrite.length; i++) { _creategetter(_readwrite[i]); _createsetter(_readwrite[i]); } // create getters for read-only attributes for (var _i = 0; _i < _readonly.length; _i++) { _creategetter(_readonly[_i]); } /** ------------------------------ getters ------------------------------ **/ /** * get the value of `rtmpconnection` from the swf. * * @method flash#rtmpconnection * @return {string} * the current value of `rtmpconnection` on the swf. */ /** * get the value of `rtmpstream` from the swf. * * @method flash#rtmpstream * @return {string} * the current value of `rtmpstream` on the swf. */ /** * get the value of `preload` from the swf. `preload` indicates * what should download before the media is interacted with. it can have the following * values: * - none: nothing should be downloaded * - metadata: poster and the first few frames of the media may be downloaded to get * media dimensions and other metadata * - auto: allow the media and metadata for the media to be downloaded before * interaction * * @method flash#preload * @return {string} * the value of `preload` from the swf. will be 'none', 'metadata', * or 'auto'. */ /** * get the value of `defaultplaybackrate` from the swf. * * @method flash#defaultplaybackrate * @return {number} * the current value of `defaultplaybackrate` on the swf. */ /** * get the value of `playbackrate` from the swf. `playbackrate` indicates * the rate at which the media is currently playing back. examples: * - if playbackrate is set to 2, media will play twice as fast. * - if playbackrate is set to 0.5, media will play half as fast. * * @method flash#playbackrate * @return {number} * the value of `playbackrate` from the swf. a number indicating * the current playback speed of the media, where 1 is normal speed. */ /** * get the value of `autoplay` from the swf. `autoplay` indicates * that the media should start to play as soon as the page is ready. * * @method flash#autoplay * @return {boolean} * - the value of `autoplay` from the swf. * - true indicates that the media ashould start as soon as the page loads. * - false indicates that the media should not start as soon as the page loads. */ /** * get the value of `loop` from the swf. `loop` indicates * that the media should return to the start of the media and continue playing once * it reaches the end. * * @method flash#loop * @return {boolean} * - the value of `loop` from the swf. * - true indicates that playback should seek back to start once * the end of a media is reached. * - false indicates that playback should not loop back to the start when the * end of the media is reached. */ /** * get the value of `mediagroup` from the swf. * * @method flash#mediagroup * @return {string} * the current value of `mediagroup` on the swf. */ /** * get the value of `controller` from the swf. * * @method flash#controller * @return {string} * the current value of `controller` on the swf. */ /** * get the value of `controls` from the swf. `controls` indicates * whether the native flash controls should be shown or hidden. * * @method flash#controls * @return {boolean} * - the value of `controls` from the swf. * - true indicates that native controls should be showing. * - false indicates that native controls should be hidden. */ /** * get the value of the `volume` from the swf. `volume` indicates the current * audio level as a percentage in decimal form. this means that 1 is 100%, 0.5 is 50%, and * so on. * * @method flash#volume * @return {number} * the volume percent as a decimal. value will be between 0-1. */ /** * get the value of the `muted` from the swf. `muted` indicates the current * audio level should be silent. * * @method flash#muted * @return {boolean} * - true if the audio should be set to silent * - false otherwise */ /** * get the value of `defaultmuted` from the swf. `defaultmuted` indicates * whether the media should start muted or not. only changes the default state of the * media. `muted` and `defaultmuted` can have different values. `muted` indicates the * current state. * * @method flash#defaultmuted * @return {boolean} * - the value of `defaultmuted` from the swf. * - true indicates that the media should start muted. * - false indicates that the media should not start muted. */ /** * get the value of `networkstate` from the swf. `networkstate` indicates * the current network state. it returns an enumeration from the following list: * - 0: network_empty * - 1: nework_idle * - 2: network_loading * - 3: network_no_source * * @method flash#networkstate * @return {number} * the value of `networkstate` from the swf. this will be a number * from the list in the description. */ /** * get the value of `readystate` from the swf. `readystate` indicates * the current state of the media element. it returns an enumeration from the * following list: * - 0: have_nothing * - 1: have_metadata * - 2: have_current_data * - 3: have_future_data * - 4: have_enough_data * * @method flash#readystate * @return {number} * the value of `readystate` from the swf. this will be a number * from the list in the description. */ /** * get the value of `readystate` from the swf. `readystate` indicates * the current state of the media element. it returns an enumeration from the * following list: * - 0: have_nothing * - 1: have_metadata * - 2: have_current_data * - 3: have_future_data * - 4: have_enough_data * * @method flash#readystate * @return {number} * the value of `readystate` from the swf. this will be a number * from the list in the description. */ /** * get the value of `initialtime` from the swf. * * @method flash#initialtime * @return {number} * the `initialtime` proprety on the swf. */ /** * get the value of `startoffsettime` from the swf. * * @method flash#startoffsettime * @return {number} * the `startoffsettime` proprety on the swf. */ /** * get the value of `paused` from the swf. `paused` indicates whether the swf * is current paused or not. * * @method flash#paused * @return {boolean} * the value of `paused` from the swf. */ /** * get the value of `ended` from the swf. `ended` indicates whether * the media has reached the end or not. * * @method flash#ended * @return {boolean} * - true indicates that the media has ended. * - false indicates that the media has not ended. * * @see [spec]{@link https://www.w3.org/tr/html5/embedded-content-0.html#dom-media-ended} */ /** * get the value of `videowidth` from the swf. `videowidth` indicates * the current width of the media in css pixels. * * @method flash#videowidth * @return {number} * the value of `videowidth` from the swf. this will be a number * in css pixels. */ /** * get the value of `videoheight` from the swf. `videoheigth` indicates * the current height of the media in css pixels. * * @method flassh.prototype.videoheight * @return {number} * the value of `videoheight` from the swf. this will be a number * in css pixels. */ /** ------------------------------ setters ------------------------------ **/ /** * set the value of `rtmpconnection` on the swf. * * @method flash#setrtmpconnection * @param {string} rtmpconnection * new value to set the `rtmpconnection` property to. */ /** * set the value of `rtmpstream` on the swf. * * @method flash#setrtmpstream * @param {string} rtmpstream * new value to set the `rtmpstream` property to. */ /** * set the value of `preload` on the swf. `preload` indicates * what should download before the media is interacted with. it can have the following * values: * - none: nothing should be downloaded * - metadata: poster and the first few frames of the media may be downloaded to get * media dimensions and other metadata * - auto: allow the media and metadata for the media to be downloaded before * interaction * * @method flash#setpreload * @param {string} preload * the value of `preload` to set on the swf. should be 'none', 'metadata', * or 'auto'. */ /** * set the value of `defaultplaybackrate` on the swf. * * @method flash#setdefaultplaybackrate * @param {number} defaultplaybackrate * new value to set the `defaultplaybackrate` property to. */ /** * set the value of `playbackrate` on the swf. `playbackrate` indicates * the rate at which the media is currently playing back. examples: * - if playbackrate is set to 2, media will play twice as fast. * - if playbackrate is set to 0.5, media will play half as fast. * * @method flash#setplaybackrate * @param {number} playbackrate * new value of `playbackrate` on the swf. a number indicating * the current playback speed of the media, where 1 is normal speed. */ /** * set the value of `autoplay` on the swf. `autoplay` indicates * that the media should start to play as soon as the page is ready. * * @method flash#setautoplay * @param {boolean} autoplay * - the value of `autoplay` from the swf. * - true indicates that the media ashould start as soon as the page loads. * - false indicates that the media should not start as soon as the page loads. */ /** * set the value of `loop` on the swf. `loop` indicates * that the media should return to the start of the media and continue playing once * it reaches the end. * * @method flash#setloop * @param {boolean} loop * - true indicates that playback should seek back to start once * the end of a media is reached. * - false indicates that playback should not loop back to the start when the * end of the media is reached. */ /** * set the value of `mediagroup` on the swf. * * @method flash#setmediagroup * @param {string} mediagroup * new value of `mediagroup` to set on the swf. */ /** * set the value of `controller` on the swf. * * @method flash#setcontroller * @param {string} controller * new value the current value of `controller` on the swf. */ /** * get the value of `controls` from the swf. `controls` indicates * whether the native flash controls should be shown or hidden. * * @method flash#controls * @return {boolean} * - the value of `controls` from the swf. * - true indicates that native controls should be showing. * - false indicates that native controls should be hidden. */ /** * set the value of the `volume` on the swf. `volume` indicates the current * audio level as a percentage in decimal form. this means that 1 is 100%, 0.5 is 50%, and * so on. * * @method flash#setvolume * @param {number} percentasdecimal * the volume percent as a decimal. value will be between 0-1. */ /** * set the value of the `muted` on the swf. `muted` indicates that the current * audio level should be silent. * * @method flash#setmuted * @param {boolean} muted * - true if the audio should be set to silent * - false otherwise */ /** * set the value of `defaultmuted` on the swf. `defaultmuted` indicates * whether the media should start muted or not. only changes the default state of the * media. `muted` and `defaultmuted` can have different values. `muted` indicates the * current state. * * @method flash#setdefaultmuted * @param {boolean} defaultmuted * - true indicates that the media should start muted. * - false indicates that the media should not start muted. */ /* flash support testing -------------------------------------------------------- */ /** * check if the flash tech is currently supported. * * @return {boolean} * - true if the flash tech is supported. * - false otherwise. */ flash.issupported = function () { return flash.version()[0] >= 10; // return swfobject.hasflashplayerversion('10'); }; // add source handler pattern functions to this tech _tech2['default'].withsourcehandlers(flash); /* * native source handler for flash, simply passes the source to the swf element. * * @property {tech~sourceobject} source * the source object * * @property {flash} tech * the instance of the flash tech */ flash.nativesourcehandler = {}; /** * check if the flash can play the given mime type. * * @param {string} type * the mimetype to check * * @return {string} * 'maybe', or '' (empty string) */ flash.nativesourcehandler.canplaytype = function (type) { if (type in flash.formats) { return 'maybe'; } return ''; }; /** * check if the media element can handle a source natively. * * @param {tech~sourceobject} source * the source object * * @param {object} [options] * options to be passed to the tech. * * @return {string} * 'maybe', or '' (empty string). */ flash.nativesourcehandler.canhandlesource = function (source, options) { var type = void 0; function guessmimetype(src) { var ext = url.getfileextension(src); if (ext) { return 'video/' + ext; } return ''; } if (!source.type) { type = guessmimetype(source.src); } else { // strip code information from the type because we don't get that specific type = source.type.replace(/;.*/, '').tolowercase(); } return flash.nativesourcehandler.canplaytype(type); }; /** * pass the source to the swf. * * @param {tech~sourceobject} source * the source object * * @param {flash} tech * the instance of the flash tech * * @param {object} [options] * the options to pass to the source */ flash.nativesourcehandler.handlesource = function (source, tech, options) { tech.setsrc(source.src); }; /** * noop for native source handler dispose, as cleanup will happen automatically. */ flash.nativesourcehandler.dispose = function () {}; // register the native source handler flash.registersourcehandler(flash.nativesourcehandler); /** * flash supported mime types. * * @constant {object} */ flash.formats = { 'video/flv': 'flv', 'video/x-flv': 'flv', 'video/mp4': 'mp4', 'video/m4v': 'mp4' }; /** * called when the the swf is "ready", and makes sure that the swf is really * ready using {@link flash#checkready} */ flash.onready = function (currswf) { var el = dom.getel(currswf); var tech = el && el.tech; // if there is no el then the tech has been disposed // and the tech element was removed from the player div if (tech && tech.el()) { // check that the flash object is really ready flash.checkready(tech); } }; /** * the swf isn't always ready when it says it is. sometimes the api functions still * need to be added to the object. if it's not ready, we set a timeout to check again * shortly. * * @param {flash} tech * the instance of the flash tech to check. */ flash.checkready = function (tech) { // stop worrying if the tech has been disposed if (!tech.el()) { return; } // check if api property exists if (tech.el().vjs_getproperty) { // tell tech it's ready tech.triggerready(); } else { // wait longer this.settimeout(function () { flash.checkready(tech); }, 50); } }; /** * trigger events from the swf on the flash tech. * * @param {number} swfid * the id of the swf that had the event * * @param {string} eventname * the name of the event to trigger */ flash.onevent = function (swfid, eventname) { var tech = dom.getel(swfid).tech; var args = array.prototype.slice.call(arguments, 2); // dispatch flash events asynchronously for two reasons: // - flash swallows any exceptions generated by javascript it // invokes // - flash is suspended until the javascript returns which may cause // playback performance issues tech.settimeout(function () { tech.trigger(eventname, args); }, 1); }; /** * log errors from the swf on the flash tech. * * @param {number} swfid * the id of the swf that had an error. * * @param {string} the error string * the error to set on the flash tech. * * @return {mediaerror|undefined} * - returns a mediaerror when err is 'srcnotfound' * - returns undefined otherwise. */ flash.onerror = function (swfid, err) { var tech = dom.getel(swfid).tech; // trigger media_err_src_not_supported if (err === 'srcnotfound') { return tech.error(4); } // trigger a custom error tech.error('flash: ' + err); }; /** * get the current version of flash that is in use on the page. * * @return {array} * an array of versions that are available. */ flash.version = function () { var version = '0,0,0'; // ie try { version = new _window2['default'].activexobject('shockwaveflash.shockwaveflash').getvariable('$version').replace(/\d+/g, ',').match(/^,?(.+),?$/)[1]; // other browsers } catch (e) { try { if (navigator.mimetypes['application/x-shockwave-flash'].enabledplugin) { version = (navigator.plugins['shockwave flash 2.0'] || navigator.plugins['shockwave flash']).description.replace(/\d+/g, ',').match(/^,?(.+),?$/)[1]; } } catch (err) { // satisfy linter } } return version.split(','); }; /** * only use for non-iframe embeds. * * @param {object} swf * the videojs-swf object. * * @param {object} flashvars * names and values to use as flash option variables. * * @param {object} params * style parameters to set on the object. * * @param {object} attributes * attributes to set on the element. * * @return {element} * the embeded flash dom element. */ flash.embed = function (swf, flashvars, params, attributes) { var code = flash.getembedcode(swf, flashvars, params, attributes); // get element by embedding code and retrieving created element var obj = dom.createel('div', { innerhtml: code }).childnodes[0]; return obj; }; /** * only use for non-iframe embeds. * * @param {object} swf * the videojs-swf object. * * @param {object} flashvars * names and values to use as flash option variables. * * @param {object} params * style parameters to set on the object. * * @param {object} attributes * attributes to set on the element. * * @return {element} * the embeded flash dom element. */ flash.getembedcode = function (swf, flashvars, params, attributes) { var objtag = ''; }); attributes = (0, _obj.assign)({ // add swf to attributes (need both for ie and others to work) data: swf, // default to 100% width/height width: '100%', height: '100%' }, attributes); // create attributes string object.getownpropertynames(attributes).foreach(function (key) { attrsstring += key + '="' + attributes[key] + '" '; }); return '' + objtag + attrsstring + '>' + paramsstring + ''; }; // run flash through the rtmp decorator (0, _flashrtmp2['default'])(flash); _component2['default'].registercomponent('flash', flash); _tech2['default'].registertech('flash', flash); exports['default'] = flash; },{"5":5,"58":58,"62":62,"81":81,"88":88,"90":90,"92":92,"95":95}],60:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _templateobject = _taggedtemplateliteralloose(['text tracks are being loaded from another origin but the crossorigin attribute isn\'t used.\n this may prevent text tracks from loading.'], ['text tracks are being loaded from another origin but the crossorigin attribute isn\'t used.\n this may prevent text tracks from loading.']); var _tech = _dereq_(62); var _tech2 = _interoprequiredefault(_tech); var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); var _dom = _dereq_(81); var dom = _interoprequirewildcard(_dom); var _url = _dereq_(92); var url = _interoprequirewildcard(_url); var _fn = _dereq_(83); var fn = _interoprequirewildcard(_fn); var _log = _dereq_(86); var _log2 = _interoprequiredefault(_log); var _tsml = _dereq_(98); var _tsml2 = _interoprequiredefault(_tsml); var _browser = _dereq_(78); var browser = _interoprequirewildcard(_browser); var _document = _dereq_(94); var _document2 = _interoprequiredefault(_document); var _window = _dereq_(95); var _window2 = _interoprequiredefault(_window); var _obj = _dereq_(88); var _mergeoptions = _dereq_(87); var _mergeoptions2 = _interoprequiredefault(_mergeoptions); var _totitlecase = _dereq_(91); var _totitlecase2 = _interoprequiredefault(_totitlecase); function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _taggedtemplateliteralloose(strings, raw) { strings.raw = raw; return strings; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file html5.js */ /** * html5 media controller - wrapper for html5 media api * * @mixes tech~soucehandleradditions * @extends tech */ var html5 = function (_tech) { _inherits(html5, _tech); /** * create an instance of this tech. * * @param {object} [options] * the key/value store of player options. * * @param {component~readycallback} ready * callback function to call when the `html5` tech is ready. */ function html5(options, ready) { _classcallcheck(this, html5); var _this = _possibleconstructorreturn(this, _tech.call(this, options, ready)); var source = options.source; var crossorigintracks = false; // set the source if one is provided // 1) check if the source is new (if not, we want to keep the original so playback isn't interrupted) // 2) check to see if the network state of the tag was failed at init, and if so, reset the source // anyway so the error gets fired. if (source && (_this.el_.currentsrc !== source.src || options.tag && options.tag.initnetworkstate_ === 3)) { _this.setsource(source); } else { _this.handlelateinit_(_this.el_); } if (_this.el_.haschildnodes()) { var nodes = _this.el_.childnodes; var nodeslength = nodes.length; var removenodes = []; while (nodeslength--) { var node = nodes[nodeslength]; var nodename = node.nodename.tolowercase(); if (nodename === 'track') { if (!_this.featuresnativetexttracks) { // empty video tag tracks so the built-in player doesn't use them also. // this may not be fast enough to stop html5 browsers from reading the tags // so we'll need to turn off any default tracks if we're manually doing // captions and subtitles. videoelement.texttracks removenodes.push(node); } else { // store htmltrackelement and texttrack to remote list _this.remotetexttrackels().addtrackelement_(node); _this.remotetexttracks().addtrack_(node.track); if (!crossorigintracks && !_this.el_.hasattribute('crossorigin') && url.iscrossorigin(node.src)) { crossorigintracks = true; } } } } for (var i = 0; i < removenodes.length; i++) { _this.el_.removechild(removenodes[i]); } } // todo: add text tracks into this list var tracktypes = ['audio', 'video']; // proxynative video/audio track tracktypes.foreach(function (type) { var eltracks = _this.el()[type + 'tracks']; var techtracks = _this[type + 'tracks'](); var capitaltype = (0, _totitlecase2['default'])(type); if (!_this['featuresnative' + capitaltype + 'tracks'] || !eltracks || !eltracks.addeventlistener) { return; } _this['handle' + capitaltype + 'trackchange_'] = function (e) { techtracks.trigger({ type: 'change', target: techtracks, currenttarget: techtracks, srcelement: techtracks }); }; _this['handle' + capitaltype + 'trackadd_'] = function (e) { return techtracks.addtrack(e.track); }; _this['handle' + capitaltype + 'trackremove_'] = function (e) { return techtracks.removetrack(e.track); }; eltracks.addeventlistener('change', _this['handle' + capitaltype + 'trackchange_']); eltracks.addeventlistener('addtrack', _this['handle' + capitaltype + 'trackadd_']); eltracks.addeventlistener('removetrack', _this['handle' + capitaltype + 'trackremove_']); _this['removeold' + capitaltype + 'tracks_'] = function (e) { return _this.removeoldtracks_(techtracks, eltracks); }; // remove (native) tracks that are not used anymore _this.on('loadstart', _this['removeold' + capitaltype + 'tracks_']); }); if (_this.featuresnativetexttracks) { if (crossorigintracks) { _log2['default'].warn((0, _tsml2['default'])(_templateobject)); } _this.handletexttrackchange_ = fn.bind(_this, _this.handletexttrackchange); _this.handletexttrackadd_ = fn.bind(_this, _this.handletexttrackadd); _this.handletexttrackremove_ = fn.bind(_this, _this.handletexttrackremove); _this.proxynativetexttracks_(); } // determine if native controls should be used // our goal should be to get the custom controls on mobile solid everywhere // so we can remove this all together. right now this will block custom // controls on touch enabled laptops like the chrome pixel if ((browser.touch_enabled || browser.is_iphone || browser.is_native_android) && options.nativecontrolsfortouch === true) { _this.setcontrols(true); } // on ios, we want to proxy `webkitbeginfullscreen` and `webkitendfullscreen` // into a `fullscreenchange` event _this.proxywebkitfullscreen_(); _this.triggerready(); return _this; } /** * dispose of `html5` media element and remove all tracks. */ html5.prototype.dispose = function dispose() { var _this2 = this; // un-proxynativetracks ['audio', 'video', 'text'].foreach(function (type) { var capitaltype = (0, _totitlecase2['default'])(type); var tl = _this2.el_[type + 'tracks']; if (tl && tl.removeeventlistener) { tl.removeeventlistener('change', _this2['handle' + capitaltype + 'trackchange_']); tl.removeeventlistener('addtrack', _this2['handle' + capitaltype + 'trackadd_']); tl.removeeventlistener('removetrack', _this2['handle' + capitaltype + 'trackremove_']); } // stop removing old text tracks if (tl) { _this2.off('loadstart', _this2['removeold' + capitaltype + 'tracks_']); } }); html5.disposemediaelement(this.el_); // tech will handle clearing of the emulated track list _tech.prototype.dispose.call(this); }; /** * create the `html5` tech's dom element. * * @return {element} * the element that gets created. */ html5.prototype.createel = function createel() { var el = this.options_.tag; // check if this browser supports moving the element into the box. // on the iphone video will break if you move the element, // so we have to create a brand new element. // if we ingested the player div, we do not need to move the media element. if (!el || !(this.options_.playerelingest || this.movingmediaelementindom)) { // if the original tag is still there, clone and remove it. if (el) { var clone = el.clonenode(true); if (el.parentnode) { el.parentnode.insertbefore(clone, el); } html5.disposemediaelement(el); el = clone; } else { el = _document2['default'].createelement('video'); // determine if native controls should be used var tagattributes = this.options_.tag && dom.getelattributes(this.options_.tag); var attributes = (0, _mergeoptions2['default'])({}, tagattributes); if (!browser.touch_enabled || this.options_.nativecontrolsfortouch !== true) { delete attributes.controls; } dom.setelattributes(el, (0, _obj.assign)(attributes, { id: this.options_.techid, 'class': 'vjs-tech' })); } el.playerid = this.options_.playerid; } // update specific tag settings, in case they were overridden var settingsattrs = ['autoplay', 'preload', 'loop', 'muted']; for (var i = settingsattrs.length - 1; i >= 0; i--) { var attr = settingsattrs[i]; var overwriteattrs = {}; if (typeof this.options_[attr] !== 'undefined') { overwriteattrs[attr] = this.options_[attr]; } dom.setelattributes(el, overwriteattrs); } return el; }; /** * this will be triggered if the loadstart event has already fired, before videojs was * ready. two known examples of when this can happen are: * 1. if we're loading the playback object after it has started loading * 2. the media is already playing the (often with autoplay on) then * * this function will fire another loadstart so that videojs can catchup. * * @fires tech#loadstart * * @return {undefined} * returns nothing. */ html5.prototype.handlelateinit_ = function handlelateinit_(el) { if (el.networkstate === 0 || el.networkstate === 3) { // the video element hasn't started loading the source yet // or didn't find a source return; } if (el.readystate === 0) { // networkstate is set synchronously but loadstart is fired at the // end of the current stack, usually before setinterval(fn, 0). // so at this point we know loadstart may have already fired or is // about to fire, and either way the player hasn't seen it yet. // we don't want to fire loadstart prematurely here and cause a // double loadstart so we'll wait and see if it happens between now // and the next loop, and fire it if not. // however, we also want to make sure it fires before loadedmetadata // which could also happen between now and the next loop, so we'll // watch for that also. var loadstartfired = false; var setloadstartfired = function setloadstartfired() { loadstartfired = true; }; this.on('loadstart', setloadstartfired); var triggerloadstart = function triggerloadstart() { // we did miss the original loadstart. make sure the player // sees loadstart before loadedmetadata if (!loadstartfired) { this.trigger('loadstart'); } }; this.on('loadedmetadata', triggerloadstart); this.ready(function () { this.off('loadstart', setloadstartfired); this.off('loadedmetadata', triggerloadstart); if (!loadstartfired) { // we did miss the original native loadstart. fire it now. this.trigger('loadstart'); } }); return; } // from here on we know that loadstart already fired and we missed it. // the other readystate events aren't as much of a problem if we double // them, so not going to go to as much trouble as loadstart to prevent // that unless we find reason to. var eventstotrigger = ['loadstart']; // loadedmetadata: newly equal to have_metadata (1) or greater eventstotrigger.push('loadedmetadata'); // loadeddata: newly increased to have_current_data (2) or greater if (el.readystate >= 2) { eventstotrigger.push('loadeddata'); } // canplay: newly increased to have_future_data (3) or greater if (el.readystate >= 3) { eventstotrigger.push('canplay'); } // canplaythrough: newly equal to have_enough_data (4) if (el.readystate >= 4) { eventstotrigger.push('canplaythrough'); } // we still need to give the player time to add event listeners this.ready(function () { eventstotrigger.foreach(function (type) { this.trigger(type); }, this); }); }; /** * add event listeners to native text track events. this adds the native text tracks * to our emulated {@link texttracklist}. */ html5.prototype.proxynativetexttracks_ = function proxynativetexttracks_() { var tt = this.el().texttracks; if (tt) { // add tracks - if player is initialised after dom loaded, texttracks // will not trigger addtrack for (var i = 0; i < tt.length; i++) { this.texttracks().addtrack_(tt[i]); } if (tt.addeventlistener) { tt.addeventlistener('change', this.handletexttrackchange_); tt.addeventlistener('addtrack', this.handletexttrackadd_); tt.addeventlistener('removetrack', this.handletexttrackremove_); } // remove (native) texttracks that are not used anymore this.on('loadstart', this.removeoldtexttracks_); } }; /** * handle any {@link texttracklist} `change` event. * * @param {eventtarget~event} e * the `change` event that caused this to run. * * @listens texttracklist#change */ html5.prototype.handletexttrackchange = function handletexttrackchange(e) { var tt = this.texttracks(); this.texttracks().trigger({ type: 'change', target: tt, currenttarget: tt, srcelement: tt }); }; /** * handle any {@link texttracklist} `addtrack` event. * * @param {eventtarget~event} e * the `addtrack` event that caused this to run. * * @listens texttracklist#addtrack */ html5.prototype.handletexttrackadd = function handletexttrackadd(e) { this.texttracks().addtrack_(e.track); }; /** * handle any {@link texttracklist} `removetrack` event. * * @param {eventtarget~event} e * the `removetrack` event that caused this to run. * * @listens texttracklist#removetrack */ html5.prototype.handletexttrackremove = function handletexttrackremove(e) { this.texttracks().removetrack_(e.track); }; /** * this function removes any {@link audiotrack}s, {@link videotrack}s, or * {@link texttrack}s that are not in the media elements tracklist. * * @param {tracklist} techtracks * html5 tech's tracklist to search through * * @param {tracklist} eltracks * html5 media elements tracklist to search trough. * * @private */ html5.prototype.removeoldtracks_ = function removeoldtracks_(techtracks, eltracks) { // this will loop over the techtracks and check if they are still used by the html5 media element // if not, they will be removed from the emulated list var removetracks = []; if (!eltracks) { return; } for (var i = 0; i < techtracks.length; i++) { var techtrack = techtracks[i]; var found = false; for (var j = 0; j < eltracks.length; j++) { if (eltracks[j] === techtrack) { found = true; break; } } if (!found) { removetracks.push(techtrack); } } for (var _i = 0; _i < removetracks.length; _i++) { var track = removetracks[_i]; techtracks.removetrack_(track); } }; /** * remove {@link texttrack}s that dont exist in the native track list from our * emulated {@link texttracklist}. * * @listens tech#loadstart */ html5.prototype.removeoldtexttracks_ = function removeoldtexttracks_(e) { var techtracks = this.texttracks(); var eltracks = this.el().texttracks; this.removeoldtracks_(techtracks, eltracks); }; /** * called by {@link player#play} to play using the `html5` `tech`. */ html5.prototype.play = function play() { var playpromise = this.el_.play(); // catch/silence error when a pause interrupts a play request // on browsers which return a promise if (playpromise !== undefined && typeof playpromise.then === 'function') { playpromise.then(null, function (e) {}); } }; /** * set current time for the `html5` tech. * * @param {number} seconds * set the current time of the media to this. */ html5.prototype.setcurrenttime = function setcurrenttime(seconds) { try { this.el_.currenttime = seconds; } catch (e) { (0, _log2['default'])(e, 'video is not ready. (video.js)'); // this.warning(videojs.warnings.videonotready); } }; /** * get the current duration of the html5 media element. * * @return {number} * the duration of the media or 0 if there is no duration. */ html5.prototype.duration = function duration() { var _this3 = this; // android chrome will report duration as infinity for vod hls until after // playback has started, which triggers the live display erroneously. // return nan if playback has not started and trigger a durationupdate once // the duration can be reliably known. if (this.el_.duration === infinity && browser.is_android && browser.is_chrome) { if (this.el_.currenttime === 0) { // wait for the first `timeupdate` with currenttime > 0 - there may be // several with 0 var checkprogress = function checkprogress() { if (_this3.el_.currenttime > 0) { // trigger durationchange for genuinely live video if (_this3.el_.duration === infinity) { _this3.trigger('durationchange'); } _this3.off('timeupdate', checkprogress); } }; this.on('timeupdate', checkprogress); return nan; } } return this.el_.duration || nan; }; /** * get the current width of the html5 media element. * * @return {number} * the width of the html5 media element. */ html5.prototype.width = function width() { return this.el_.offsetwidth; }; /** * get the current height of the html5 media element. * * @return {number} * the heigth of the html5 media element. */ html5.prototype.height = function height() { return this.el_.offsetheight; }; /** * proxy ios `webkitbeginfullscreen` and `webkitendfullscreen` into * `fullscreenchange` event. * * @private * @fires fullscreenchange * @listens webkitendfullscreen * @listens webkitbeginfullscreen * @listens webkitbeginfullscreen */ html5.prototype.proxywebkitfullscreen_ = function proxywebkitfullscreen_() { var _this4 = this; if (!('webkitdisplayingfullscreen' in this.el_)) { return; } var endfn = function endfn() { this.trigger('fullscreenchange', { isfullscreen: false }); }; var beginfn = function beginfn() { this.one('webkitendfullscreen', endfn); this.trigger('fullscreenchange', { isfullscreen: true }); }; this.on('webkitbeginfullscreen', beginfn); this.on('dispose', function () { _this4.off('webkitbeginfullscreen', beginfn); _this4.off('webkitendfullscreen', endfn); }); }; /** * check if fullscreen is supported on the current playback device. * * @return {boolean} * - true if fullscreen is supported. * - false if fullscreen is not supported. */ html5.prototype.supportsfullscreen = function supportsfullscreen() { if (typeof this.el_.webkitenterfullscreen === 'function') { var useragent = _window2['default'].navigator && _window2['default'].navigator.useragent || ''; // seems to be broken in chromium/chrome && safari in leopard if (/android/.test(useragent) || !/chrome|mac os x 10.5/.test(useragent)) { return true; } } return false; }; /** * request that the `html5` tech enter fullscreen. */ html5.prototype.enterfullscreen = function enterfullscreen() { var video = this.el_; if (video.paused && video.networkstate <= video.have_metadata) { // attempt to prime the video element for programmatic access // this isn't necessary on the desktop but shouldn't hurt this.el_.play(); // playing and pausing synchronously during the transition to fullscreen // can get ios ~6.1 devices into a play/pause loop this.settimeout(function () { video.pause(); video.webkitenterfullscreen(); }, 0); } else { video.webkitenterfullscreen(); } }; /** * request that the `html5` tech exit fullscreen. */ html5.prototype.exitfullscreen = function exitfullscreen() { this.el_.webkitexitfullscreen(); }; /** * a getter/setter for the `html5` tech's source object. * > note: please use {@link html5#setsource} * * @param {tech~sourceobject} [src] * the source object you want to set on the `html5` techs element. * * @return {tech~sourceobject|undefined} * - the current source object when a source is not passed in. * - undefined when setting * * @deprecated since version 5. */ html5.prototype.src = function src(_src) { if (_src === undefined) { return this.el_.src; } // setting src through `src` instead of `setsrc` will be deprecated this.setsrc(_src); }; /** * reset the tech by removing all sources and then calling * {@link html5.resetmediaelement}. */ html5.prototype.reset = function reset() { html5.resetmediaelement(this.el_); }; /** * get the current source on the `html5` tech. falls back to returning the source from * the html5 media element. * * @return {tech~sourceobject} * the current source object from the html5 tech. with a fallback to the * elements source. */ html5.prototype.currentsrc = function currentsrc() { if (this.currentsource_) { return this.currentsource_.src; } return this.el_.currentsrc; }; /** * set controls attribute for the html5 media element. * * @param {string} val * value to set the controls attribute to */ html5.prototype.setcontrols = function setcontrols(val) { this.el_.controls = !!val; }; /** * create and returns a remote {@link texttrack} object. * * @param {string} kind * `texttrack` kind (subtitles, captions, descriptions, chapters, or metadata) * * @param {string} [label] * label to identify the text track * * @param {string} [language] * two letter language abbreviation * * @return {texttrack} * the texttrack that gets created. */ html5.prototype.addtexttrack = function addtexttrack(kind, label, language) { if (!this.featuresnativetexttracks) { return _tech.prototype.addtexttrack.call(this, kind, label, language); } return this.el_.addtexttrack(kind, label, language); }; /** * creates either native texttrack or an emulated texttrack depending * on the value of `featuresnativetexttracks` * * @param {object} options * the object should contain the options to intialize the texttrack with. * * @param {string} [options.kind] * `texttrack` kind (subtitles, captions, descriptions, chapters, or metadata). * * @param {string} [options.label]. * label to identify the text track * * @param {string} [options.language] * two letter language abbreviation. * * @param {boolean} [options.default] * default this track to on. * * @param {string} [options.id] * the internal id to assign this track. * * @param {string} [options.src] * a source url for the track. * * @return {htmltrackelement} * the track element that gets created. */ html5.prototype.createremotetexttrack = function createremotetexttrack(options) { if (!this.featuresnativetexttracks) { return _tech.prototype.createremotetexttrack.call(this, options); } var htmltrackelement = _document2['default'].createelement('track'); if (options.kind) { htmltrackelement.kind = options.kind; } if (options.label) { htmltrackelement.label = options.label; } if (options.language || options.srclang) { htmltrackelement.srclang = options.language || options.srclang; } if (options['default']) { htmltrackelement['default'] = options['default']; } if (options.id) { htmltrackelement.id = options.id; } if (options.src) { htmltrackelement.src = options.src; } return htmltrackelement; }; /** * creates a remote text track object and returns an html track element. * * @param {object} options the object should contain values for * kind, language, label, and src (location of the webvtt file) * @param {boolean} [manualcleanup=true] if set to false, the texttrack will be * automatically removed from the video element whenever the source changes * @return {htmltrackelement} an html track element. * this can be an emulated {@link htmltrackelement} or a native one. * @deprecated the default value of the "manualcleanup" parameter will default * to "false" in upcoming versions of video.js */ html5.prototype.addremotetexttrack = function addremotetexttrack(options, manualcleanup) { var htmltrackelement = _tech.prototype.addremotetexttrack.call(this, options, manualcleanup); if (this.featuresnativetexttracks) { this.el().appendchild(htmltrackelement); } return htmltrackelement; }; /** * remove remote `texttrack` from `texttracklist` object * * @param {texttrack} track * `texttrack` object to remove */ html5.prototype.removeremotetexttrack = function removeremotetexttrack(track) { _tech.prototype.removeremotetexttrack.call(this, track); if (this.featuresnativetexttracks) { var tracks = this.$$('track'); var i = tracks.length; while (i--) { if (track === tracks[i] || track === tracks[i].track) { this.el().removechild(tracks[i]); } } } }; return html5; }(_tech2['default']); /* html5 support testing ---------------------------------------------------- */ if (dom.isreal()) { /** * element for testing browser html5 media capabilities * * @type {element} * @constant * @private */ html5.test_vid = _document2['default'].createelement('video'); var track = _document2['default'].createelement('track'); track.kind = 'captions'; track.srclang = 'en'; track.label = 'english'; html5.test_vid.appendchild(track); } /** * check if html5 media is supported by this browser/device. * * @return {boolean} * - true if html5 media is supported. * - false if html5 media is not supported. */ html5.issupported = function () { // ie9 with no media player is a liar! (#984) try { html5.test_vid.volume = 0.5; } catch (e) { return false; } return !!(html5.test_vid && html5.test_vid.canplaytype); }; /** * check if the volume can be changed in this browser/device. * volume cannot be changed in a lot of mobile devices. * specifically, it can't be changed from 1 on ios. * * @return {boolean} * - true if volume can be controlled * - false otherwise */ html5.cancontrolvolume = function () { // ie will error if windows media player not installed #3315 try { var volume = html5.test_vid.volume; html5.test_vid.volume = volume / 2 + 0.1; return volume !== html5.test_vid.volume; } catch (e) { return false; } }; /** * check if the playback rate can be changed in this browser/device. * * @return {boolean} * - true if playback rate can be controlled * - false otherwise */ html5.cancontrolplaybackrate = function () { // playback rate api is implemented in android chrome, but doesn't do anything // https://github.com/videojs/video.js/issues/3180 if (browser.is_android && browser.is_chrome) { return false; } // ie will error if windows media player not installed #3315 try { var playbackrate = html5.test_vid.playbackrate; html5.test_vid.playbackrate = playbackrate / 2 + 0.1; return playbackrate !== html5.test_vid.playbackrate; } catch (e) { return false; } }; /** * check to see if native `texttrack`s are supported by this browser/device. * * @return {boolean} * - true if native `texttrack`s are supported. * - false otherwise */ html5.supportsnativetexttracks = function () { return browser.is_any_safari; }; /** * check to see if native `videotrack`s are supported by this browser/device * * @return {boolean} * - true if native `videotrack`s are supported. * - false otherwise */ html5.supportsnativevideotracks = function () { return !!(html5.test_vid && html5.test_vid.videotracks); }; /** * check to see if native `audiotrack`s are supported by this browser/device * * @return {boolean} * - true if native `audiotrack`s are supported. * - false otherwise */ html5.supportsnativeaudiotracks = function () { return !!(html5.test_vid && html5.test_vid.audiotracks); }; /** * an array of events available on the html5 tech. * * @private * @type {array} */ html5.events = ['loadstart', 'suspend', 'abort', 'error', 'emptied', 'stalled', 'loadedmetadata', 'loadeddata', 'canplay', 'canplaythrough', 'playing', 'waiting', 'seeking', 'seeked', 'ended', 'durationchange', 'timeupdate', 'progress', 'play', 'pause', 'ratechange', 'volumechange']; /** * boolean indicating whether the `tech` supports volume control. * * @type {boolean} * @default {@link html5.cancontrolvolume} */ html5.prototype.featuresvolumecontrol = html5.cancontrolvolume(); /** * boolean indicating whether the `tech` supports changing the speed at which the media * plays. examples: * - set player to play 2x (twice) as fast * - set player to play 0.5x (half) as fast * * @type {boolean} * @default {@link html5.cancontrolplaybackrate} */ html5.prototype.featuresplaybackrate = html5.cancontrolplaybackrate(); /** * boolean indicating whether the `html5` tech currently supports the media element * moving in the dom. ios breaks if you move the media element, so this is set this to * false there. everywhere else this should be true. * * @type {boolean} * @default */ html5.prototype.movingmediaelementindom = !browser.is_ios; // todo: previous comment: no longer appears to be used. can probably be removed. // is this true? /** * boolean indicating whether the `html5` tech currently supports automatic media resize * when going into fullscreen. * * @type {boolean} * @default */ html5.prototype.featuresfullscreenresize = true; /** * boolean indicating whether the `html5` tech currently supports the progress event. * if this is false, manual `progress` events will be triggred instead. * * @type {boolean} * @default */ html5.prototype.featuresprogressevents = true; /** * boolean indicating whether the `html5` tech currently supports the timeupdate event. * if this is false, manual `timeupdate` events will be triggred instead. * * @default */ html5.prototype.featurestimeupdateevents = true; /** * boolean indicating whether the `html5` tech currently supports native `texttrack`s. * * @type {boolean} * @default {@link html5.supportsnativetexttracks} */ html5.prototype.featuresnativetexttracks = html5.supportsnativetexttracks(); /** * boolean indicating whether the `html5` tech currently supports native `videotrack`s. * * @type {boolean} * @default {@link html5.supportsnativevideotracks} */ html5.prototype.featuresnativevideotracks = html5.supportsnativevideotracks(); /** * boolean indicating whether the `html5` tech currently supports native `audiotrack`s. * * @type {boolean} * @default {@link html5.supportsnativeaudiotracks} */ html5.prototype.featuresnativeaudiotracks = html5.supportsnativeaudiotracks(); // html5 feature detection and device fixes --------------------------------- // var canplaytype = html5.test_vid && html5.test_vid.constructor.prototype.canplaytype; var mpegurlre = /^application\/(?:x-|vnd\.apple\.)mpegurl/i; var mp4re = /^video\/mp4/i; html5.patchcanplaytype = function () { // android 4.0 and above can play hls to some extent but it reports being unable to do so if (browser.android_version >= 4.0 && !browser.is_firefox) { html5.test_vid.constructor.prototype.canplaytype = function (type) { if (type && mpegurlre.test(type)) { return 'maybe'; } return canplaytype.call(this, type); }; // override android 2.2 and less canplaytype method which is broken } else if (browser.is_old_android) { html5.test_vid.constructor.prototype.canplaytype = function (type) { if (type && mp4re.test(type)) { return 'maybe'; } return canplaytype.call(this, type); }; } }; html5.unpatchcanplaytype = function () { var r = html5.test_vid.constructor.prototype.canplaytype; html5.test_vid.constructor.prototype.canplaytype = canplaytype; return r; }; // by default, patch the media element html5.patchcanplaytype(); html5.disposemediaelement = function (el) { if (!el) { return; } if (el.parentnode) { el.parentnode.removechild(el); } // remove any child track or source nodes to prevent their loading while (el.haschildnodes()) { el.removechild(el.firstchild); } // remove any src reference. not setting `src=''` because that causes a warning // in firefox el.removeattribute('src'); // force the media element to update its loading state by calling load() // however ie on windows 7n has a bug that throws an error so need a try/catch (#793) if (typeof el.load === 'function') { // wrapping in an iife so it's not deoptimized (#1060#discussion_r10324473) (function () { try { el.load(); } catch (e) { // not supported } })(); } }; html5.resetmediaelement = function (el) { if (!el) { return; } var sources = el.queryselectorall('source'); var i = sources.length; while (i--) { el.removechild(sources[i]); } // remove any src reference. // not setting `src=''` because that throws an error el.removeattribute('src'); if (typeof el.load === 'function') { // wrapping in an iife so it's not deoptimized (#1060#discussion_r10324473) (function () { try { el.load(); } catch (e) { // satisfy linter } })(); } }; /* native html5 element property wrapping ----------------------------------- */ // wrap native properties with a getter [ /** * get the value of `paused` from the media element. `paused` indicates whether the media element * is currently paused or not. * * @method html5#paused * @return {boolean} * the value of `paused` from the media element. * * @see [spec]{@link https://www.w3.org/tr/html5/embedded-content-0.html#dom-media-paused} */ 'paused', /** * get the value of `currenttime` from the media element. `currenttime` indicates * the current second that the media is at in playback. * * @method html5#currenttime * @return {number} * the value of `currenttime` from the media element. * * @see [spec]{@link https://www.w3.org/tr/html5/embedded-content-0.html#dom-media-currenttime} */ 'currenttime', /** * get the value of `buffered` from the media element. `buffered` is a `timerange` * object that represents the parts of the media that are already downloaded and * available for playback. * * @method html5#buffered * @return {timerange} * the value of `buffered` from the media element. * * @see [spec]{@link https://www.w3.org/tr/html5/embedded-content-0.html#dom-media-buffered} */ 'buffered', /** * get the value of `volume` from the media element. `volume` indicates * the current playback volume of audio for a media. `volume` will be a value from 0 * (silent) to 1 (loudest and default). * * @method html5#volume * @return {number} * the value of `volume` from the media element. value will be between 0-1. * * @see [spec]{@link https://www.w3.org/tr/html5/embedded-content-0.html#dom-a-volume} */ 'volume', /** * get the value of `muted` from the media element. `muted` indicates * that the volume for the media should be set to silent. this does not actually change * the `volume` attribute. * * @method html5#muted * @return {boolean} * - true if the value of `volume` should be ignored and the audio set to silent. * - false if the value of `volume` should be used. * * @see [spec]{@link https://www.w3.org/tr/html5/embedded-content-0.html#dom-media-muted} */ 'muted', /** * get the value of `poster` from the media element. `poster` indicates * that the url of an image file that can/will be shown when no media data is available. * * @method html5#poster * @return {string} * the value of `poster` from the media element. value will be a url to an * image. * * @see [spec]{@link https://www.w3.org/tr/html5/embedded-content-0.html#attr-video-poster} */ 'poster', /** * get the value of `preload` from the media element. `preload` indicates * what should download before the media is interacted with. it can have the following * values: * - none: nothing should be downloaded * - metadata: poster and the first few frames of the media may be downloaded to get * media dimensions and other metadata * - auto: allow the media and metadata for the media to be downloaded before * interaction * * @method html5#preload * @return {string} * the value of `preload` from the media element. will be 'none', 'metadata', * or 'auto'. * * @see [spec]{@link https://www.w3.org/tr/html5/embedded-content-0.html#attr-media-preload} */ 'preload', /** * get the value of `autoplay` from the media element. `autoplay` indicates * that the media should start to play as soon as the page is ready. * * @method html5#autoplay * @return {boolean} * - the value of `autoplay` from the media element. * - true indicates that the media should start as soon as the page loads. * - false indicates that the media should not start as soon as the page loads. * * @see [spec]{@link https://www.w3.org/tr/html5/embedded-content-0.html#attr-media-autoplay} */ 'autoplay', /** * get the value of `controls` from the media element. `controls` indicates * whether the native media controls should be shown or hidden. * * @method html5#controls * @return {boolean} * - the value of `controls` from the media element. * - true indicates that native controls should be showing. * - false indicates that native controls should be hidden. * * @see [spec]{@link https://www.w3.org/tr/html5/embedded-content-0.html#attr-media-controls} */ 'controls', /** * get the value of `loop` from the media element. `loop` indicates * that the media should return to the start of the media and continue playing once * it reaches the end. * * @method html5#loop * @return {boolean} * - the value of `loop` from the media element. * - true indicates that playback should seek back to start once * the end of a media is reached. * - false indicates that playback should not loop back to the start when the * end of the media is reached. * * @see [spec]{@link https://www.w3.org/tr/html5/embedded-content-0.html#attr-media-loop} */ 'loop', /** * get the value of the `error` from the media element. `error` indicates any * mediaerror that may have occured during playback. if error returns null there is no * current error. * * @method html5#error * @return {mediaerror|null} * the value of `error` from the media element. will be `mediaerror` if there * is a current error and null otherwise. * * @see [spec]{@link https://www.w3.org/tr/html5/embedded-content-0.html#dom-media-error} */ 'error', /** * get the value of `seeking` from the media element. `seeking` indicates whether the * media is currently seeking to a new position or not. * * @method html5#seeking * @return {boolean} * - the value of `seeking` from the media element. * - true indicates that the media is currently seeking to a new position. * - flase indicates that the media is not seeking to a new position at this time. * * @see [spec]{@link https://www.w3.org/tr/html5/embedded-content-0.html#dom-media-seeking} */ 'seeking', /** * get the value of `seekable` from the media element. `seekable` returns a * `timerange` object indicating ranges of time that can currently be `seeked` to. * * @method html5#seekable * @return {timerange} * the value of `seekable` from the media element. a `timerange` object * indicating the current ranges of time that can be seeked to. * * @see [spec]{@link https://www.w3.org/tr/html5/embedded-content-0.html#dom-media-seekable} */ 'seekable', /** * get the value of `ended` from the media element. `ended` indicates whether * the media has reached the end or not. * * @method html5#ended * @return {boolean} * - the value of `ended` from the media element. * - true indicates that the media has ended. * - false indicates that the media has not ended. * * @see [spec]{@link https://www.w3.org/tr/html5/embedded-content-0.html#dom-media-ended} */ 'ended', /** * get the value of `defaultmuted` from the media element. `defaultmuted` indicates * whether the media should start muted or not. only changes the default state of the * media. `muted` and `defaultmuted` can have different values. `muted` indicates the * current state. * * @method html5#defaultmuted * @return {boolean} * - the value of `defaultmuted` from the media element. * - true indicates that the media should start muted. * - false indicates that the media should not start muted * * @see [spec]{@link https://www.w3.org/tr/html5/embedded-content-0.html#dom-media-defaultmuted} */ 'defaultmuted', /** * get the value of `playbackrate` from the media element. `playbackrate` indicates * the rate at which the media is currently playing back. examples: * - if playbackrate is set to 2, media will play twice as fast. * - if playbackrate is set to 0.5, media will play half as fast. * * @method html5#playbackrate * @return {number} * the value of `playbackrate` from the media element. a number indicating * the current playback speed of the media, where 1 is normal speed. * * @see [spec]{@link https://www.w3.org/tr/html5/embedded-content-0.html#dom-media-playbackrate} */ 'playbackrate', /** * get the value of `played` from the media element. `played` returns a `timerange` * object representing points in the media timeline that have been played. * * @method html5#played * @return {timerange} * the value of `played` from the media element. a `timerange` object indicating * the ranges of time that have been played. * * @see [spec]{@link https://www.w3.org/tr/html5/embedded-content-0.html#dom-media-played} */ 'played', /** * get the value of `networkstate` from the media element. `networkstate` indicates * the current network state. it returns an enumeration from the following list: * - 0: network_empty * - 1: nework_idle * - 2: network_loading * - 3: network_no_source * * @method html5#networkstate * @return {number} * the value of `networkstate` from the media element. this will be a number * from the list in the description. * * @see [spec] {@link https://www.w3.org/tr/html5/embedded-content-0.html#dom-media-networkstate} */ 'networkstate', /** * get the value of `readystate` from the media element. `readystate` indicates * the current state of the media element. it returns an enumeration from the * following list: * - 0: have_nothing * - 1: have_metadata * - 2: have_current_data * - 3: have_future_data * - 4: have_enough_data * * @method html5#readystate * @return {number} * the value of `readystate` from the media element. this will be a number * from the list in the description. * * @see [spec] {@link https://www.w3.org/tr/html5/embedded-content-0.html#ready-states} */ 'readystate', /** * get the value of `videowidth` from the video element. `videowidth` indicates * the current width of the video in css pixels. * * @method html5#videowidth * @return {number} * the value of `videowidth` from the video element. this will be a number * in css pixels. * * @see [spec] {@link https://www.w3.org/tr/html5/embedded-content-0.html#dom-video-videowidth} */ 'videowidth', /** * get the value of `videoheight` from the video element. `videoheigth` indicates * the current height of the video in css pixels. * * @method html5#videoheight * @return {number} * the value of `videoheight` from the video element. this will be a number * in css pixels. * * @see [spec] {@link https://www.w3.org/tr/html5/embedded-content-0.html#dom-video-videowidth} */ 'videoheight'].foreach(function (prop) { html5.prototype[prop] = function () { return this.el_[prop]; }; }); // wrap native properties with a setter in this format: // set + totitlecase(name) [ /** * set the value of `volume` on the media element. `volume` indicates the current * audio level as a percentage in decimal form. this means that 1 is 100%, 0.5 is 50%, and * so on. * * @method html5#setvolume * @param {number} percentasdecimal * the volume percent as a decimal. valid range is from 0-1. * * @see [spec]{@link https://www.w3.org/tr/html5/embedded-content-0.html#dom-a-volume} */ 'volume', /** * set the value of `muted` on the media element. `muted` indicates the current * audio level should be silent. * * @method html5#setmuted * @param {boolean} muted * - true if the audio should be set to silent * - false otherwise * * @see [spec]{@link https://www.w3.org/tr/html5/embedded-content-0.html#dom-media-muted} */ 'muted', /** * set the value of `src` on the media element. `src` indicates the current * {@link tech~sourceobject} for the media. * * @method html5#setsrc * @param {tech~sourceobject} src * the source object to set as the current source. * * @see [spec]{@link https://www.w3.org/tr/html5/embedded-content-0.html#dom-media-src} */ 'src', /** * set the value of `poster` on the media element. `poster` is the url to * an image file that can/will be shown when no media data is available. * * @method html5#setposter * @param {string} poster * the url to an image that should be used as the `poster` for the media * element. * * @see [spec]{@link https://www.w3.org/tr/html5/embedded-content-0.html#attr-media-poster} */ 'poster', /** * set the value of `preload` on the media element. `preload` indicates * what should download before the media is interacted with. it can have the following * values: * - none: nothing should be downloaded * - metadata: poster and the first few frames of the media may be downloaded to get * media dimensions and other metadata * - auto: allow the media and metadata for the media to be downloaded before * interaction * * @method html5#setpreload * @param {string} preload * the value of `preload` to set on the media element. must be 'none', 'metadata', * or 'auto'. * * @see [spec]{@link https://www.w3.org/tr/html5/embedded-content-0.html#attr-media-preload} */ 'preload', /** * set the value of `autoplay` on the media element. `autoplay` indicates * that the media should start to play as soon as the page is ready. * * @method html5#setautoplay * @param {boolean} autoplay * - true indicates that the media should start as soon as the page loads. * - false indicates that the media should not start as soon as the page loads. * * @see [spec]{@link https://www.w3.org/tr/html5/embedded-content-0.html#attr-media-autoplay} */ 'autoplay', /** * set the value of `loop` on the media element. `loop` indicates * that the media should return to the start of the media and continue playing once * it reaches the end. * * @method html5#setloop * @param {boolean} loop * - true indicates that playback should seek back to start once * the end of a media is reached. * - false indicates that playback should not loop back to the start when the * end of the media is reached. * * @see [spec]{@link https://www.w3.org/tr/html5/embedded-content-0.html#attr-media-loop} */ 'loop', /** * set the value of `playbackrate` on the media element. `playbackrate` indicates * the rate at which the media should play back. examples: * - if playbackrate is set to 2, media will play twice as fast. * - if playbackrate is set to 0.5, media will play half as fast. * * @method html5#setplaybackrate * @return {number} * the value of `playbackrate` from the media element. a number indicating * the current playback speed of the media, where 1 is normal speed. * * @see [spec]{@link https://www.w3.org/tr/html5/embedded-content-0.html#dom-media-playbackrate} */ 'playbackrate'].foreach(function (prop) { html5.prototype['set' + (0, _totitlecase2['default'])(prop)] = function (v) { this.el_[prop] = v; }; }); // wrap native functions with a function [ /** * a wrapper around the media elements `pause` function. this will call the `html5` * media elements `pause` function. * * @method html5#pause * @see [spec]{@link https://www.w3.org/tr/html5/embedded-content-0.html#dom-media-pause} */ 'pause', /** * a wrapper around the media elements `load` function. this will call the `html5`s * media element `load` function. * * @method html5#load * @see [spec]{@link https://www.w3.org/tr/html5/embedded-content-0.html#dom-media-load} */ 'load'].foreach(function (prop) { html5.prototype[prop] = function () { return this.el_[prop](); }; }); _tech2['default'].withsourcehandlers(html5); /** * native source handler for html5, simply passes the source to the media element. * * @proprety {tech~sourceobject} source * the source object * * @proprety {html5} tech * the instance of the html5 tech. */ html5.nativesourcehandler = {}; /** * check if the media element can play the given mime type. * * @param {string} type * the mimetype to check * * @return {string} * 'probably', 'maybe', or '' (empty string) */ html5.nativesourcehandler.canplaytype = function (type) { // ie9 on windows 7 without mediaplayer throws an error here // https://github.com/videojs/video.js/issues/519 try { return html5.test_vid.canplaytype(type); } catch (e) { return ''; } }; /** * check if the media element can handle a source natively. * * @param {tech~sourceobject} source * the source object * * @param {object} [options] * options to be passed to the tech. * * @return {string} * 'probably', 'maybe', or '' (empty string). */ html5.nativesourcehandler.canhandlesource = function (source, options) { // if a type was provided we should rely on that if (source.type) { return html5.nativesourcehandler.canplaytype(source.type); // if no type, fall back to checking 'video/[extension]' } else if (source.src) { var ext = url.getfileextension(source.src); return html5.nativesourcehandler.canplaytype('video/' + ext); } return ''; }; /** * pass the source to the native media element. * * @param {tech~sourceobject} source * the source object * * @param {html5} tech * the instance of the html5 tech * * @param {object} [options] * the options to pass to the source */ html5.nativesourcehandler.handlesource = function (source, tech, options) { tech.setsrc(source.src); }; /** * a noop for the native dispose function, as cleanup is not needed. */ html5.nativesourcehandler.dispose = function () {}; // register the native source handler html5.registersourcehandler(html5.nativesourcehandler); _component2['default'].registercomponent('html5', html5); _tech2['default'].registertech('html5', html5); exports['default'] = html5; },{"5":5,"62":62,"78":78,"81":81,"83":83,"86":86,"87":87,"88":88,"91":91,"92":92,"94":94,"95":95,"98":98}],61:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); var _tech = _dereq_(62); var _tech2 = _interoprequiredefault(_tech); var _totitlecase = _dereq_(91); var _totitlecase2 = _interoprequiredefault(_totitlecase); function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file loader.js */ /** * the `medialoader` is the `component` that decides which playback technology to load * when a player is initialized. * * @extends component */ var medialoader = function (_component) { _inherits(medialoader, _component); /** * create an instance of this class. * * @param {player} player * the `player` that this class should attach to. * * @param {object} [options] * the key/value stroe of player options. * * @param {component~readycallback} [ready] * the function that is run when this component is ready. */ function medialoader(player, options, ready) { _classcallcheck(this, medialoader); // if there are no sources when the player is initialized, // load the first supported playback technology. var _this = _possibleconstructorreturn(this, _component.call(this, player, options, ready)); if (!options.playeroptions.sources || options.playeroptions.sources.length === 0) { for (var i = 0, j = options.playeroptions.techorder; i < j.length; i++) { var techname = (0, _totitlecase2['default'])(j[i]); var tech = _tech2['default'].gettech(techname); // support old behavior of techs being registered as components. // remove once that deprecated behavior is removed. if (!techname) { tech = _component2['default'].getcomponent(techname); } // check if the browser supports this technology if (tech && tech.issupported()) { player.loadtech_(techname); break; } } } else { // loop through playback technologies (html5, flash) and check for support. // then load the best source. // a few assumptions here: // all playback technologies respect preload false. player.src(options.playeroptions.sources); } return _this; } return medialoader; }(_component2['default']); _component2['default'].registercomponent('medialoader', medialoader); exports['default'] = medialoader; },{"5":5,"62":62,"91":91}],62:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); var _htmltrackelement = _dereq_(66); var _htmltrackelement2 = _interoprequiredefault(_htmltrackelement); var _htmltrackelementlist = _dereq_(65); var _htmltrackelementlist2 = _interoprequiredefault(_htmltrackelementlist); var _mergeoptions = _dereq_(87); var _mergeoptions2 = _interoprequiredefault(_mergeoptions); var _texttrack = _dereq_(72); var _texttrack2 = _interoprequiredefault(_texttrack); var _texttracklist = _dereq_(70); var _texttracklist2 = _interoprequiredefault(_texttracklist); var _videotracklist = _dereq_(76); var _videotracklist2 = _interoprequiredefault(_videotracklist); var _audiotracklist = _dereq_(63); var _audiotracklist2 = _interoprequiredefault(_audiotracklist); var _fn = _dereq_(83); var fn = _interoprequirewildcard(_fn); var _log = _dereq_(86); var _log2 = _interoprequiredefault(_log); var _timeranges = _dereq_(90); var _buffer = _dereq_(79); var _mediaerror = _dereq_(46); var _mediaerror2 = _interoprequiredefault(_mediaerror); var _window = _dereq_(95); var _window2 = _interoprequiredefault(_window); var _document = _dereq_(94); var _document2 = _interoprequiredefault(_document); var _obj = _dereq_(88); function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file tech.js */ /** * an object containing a structure like: `{src: 'url', type: 'mimetype'}` or string * that just contains the src url alone. * * `var sourceobject = {src: 'http://ex.com/video.mp4', type: 'video/mp4'};` * `var sourcestring = 'http://example.com/some-video.mp4';` * * @typedef {object|string} tech~sourceobject * * @property {string} src * the url to the source * * @property {string} type * the mime type of the source */ /** * a function used by {@link tech} to create a new {@link texttrack}. * * @param {tech} self * an instance of the tech class. * * @param {string} kind * `texttrack` kind (subtitles, captions, descriptions, chapters, or metadata) * * @param {string} [label] * label to identify the text track * * @param {string} [language] * two letter language abbreviation * * @param {object} [options={}] * an object with additional text track options * * @return {texttrack} * the text track that was created. */ function createtrackhelper(self, kind, label, language) { var options = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {}; var tracks = self.texttracks(); options.kind = kind; if (label) { options.label = label; } if (language) { options.language = language; } options.tech = self; var track = new _texttrack2['default'](options); tracks.addtrack_(track); return track; } /** * this is the base class for media playback technology controllers, such as * {@link flash} and {@link html5} * * @extends component */ var tech = function (_component) { _inherits(tech, _component); /** * create an instance of this tech. * * @param {object} [options] * the key/value store of player options. * * @param {component~readycallback} ready * callback function to call when the `html5` tech is ready. */ function tech() { var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var ready = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {}; _classcallcheck(this, tech); // we don't want the tech to report user activity automatically. // this is done manually in addcontrolslisteners options.reporttouchactivity = false; // keep track of whether the current source has played at all to // implement a very limited played() var _this = _possibleconstructorreturn(this, _component.call(this, null, options, ready)); _this.hasstarted_ = false; _this.on('playing', function () { this.hasstarted_ = true; }); _this.on('loadstart', function () { this.hasstarted_ = false; }); _this.texttracks_ = options.texttracks; _this.videotracks_ = options.videotracks; _this.audiotracks_ = options.audiotracks; // manually track progress in cases where the browser/flash player doesn't report it. if (!_this.featuresprogressevents) { _this.manualprogresson(); } // manually track timeupdates in cases where the browser/flash player doesn't report it. if (!_this.featurestimeupdateevents) { _this.manualtimeupdateson(); } ['text', 'audio', 'video'].foreach(function (track) { if (options['native' + track + 'tracks'] === false) { _this['featuresnative' + track + 'tracks'] = false; } }); if (options.nativecaptions === false) { _this.featuresnativetexttracks = false; } if (!_this.featuresnativetexttracks) { _this.emulatetexttracks(); } _this.autoremotetexttracks_ = new _texttracklist2['default'](); _this.inittexttracklisteners(); _this.inittracklisteners(); // turn on component tap events only if not using native controls if (!options.nativecontrolsfortouch) { _this.emittapevents(); } if (_this.constructor) { _this.name_ = _this.constructor.name || 'unknown tech'; } return _this; } /* fallbacks for unsupported event types ================================================================================ */ /** * polyfill the `progress` event for browsers that don't support it natively. * * @see {@link tech#trackprogress} */ tech.prototype.manualprogresson = function manualprogresson() { this.on('durationchange', this.ondurationchange); this.manualprogress = true; // trigger progress watching when a source begins loading this.one('ready', this.trackprogress); }; /** * turn off the polyfill for `progress` events that was created in * {@link tech#manualprogresson} */ tech.prototype.manualprogressoff = function manualprogressoff() { this.manualprogress = false; this.stoptrackingprogress(); this.off('durationchange', this.ondurationchange); }; /** * this is used to trigger a `progress` event when the buffered percent changes. it * sets an interval function that will be called every 500 milliseconds to check if the * buffer end percent has changed. * * > this function is called by {@link tech#manualprogresson} * * @param {eventtarget~event} event * the `ready` event that caused this to run. * * @listens tech#ready * @fires tech#progress */ tech.prototype.trackprogress = function trackprogress(event) { this.stoptrackingprogress(); this.progressinterval = this.setinterval(fn.bind(this, function () { // don't trigger unless buffered amount is greater than last time var numbufferedpercent = this.bufferedpercent(); if (this.bufferedpercent_ !== numbufferedpercent) { /** * see {@link player#progress} * * @event tech#progress * @type {eventtarget~event} */ this.trigger('progress'); } this.bufferedpercent_ = numbufferedpercent; if (numbufferedpercent === 1) { this.stoptrackingprogress(); } }), 500); }; /** * update our internal duration on a `durationchange` event by calling * {@link tech#duration}. * * @param {eventtarget~event} event * the `durationchange` event that caused this to run. * * @listens tech#durationchange */ tech.prototype.ondurationchange = function ondurationchange(event) { this.duration_ = this.duration(); }; /** * get and create a `timerange` object for buffering. * * @return {timerange} * the time range object that was created. */ tech.prototype.buffered = function buffered() { return (0, _timeranges.createtimerange)(0, 0); }; /** * get the percentage of the current video that is currently buffered. * * @return {number} * a number from 0 to 1 that represents the decimal percentage of the * video that is buffered. * */ tech.prototype.bufferedpercent = function bufferedpercent() { return (0, _buffer.bufferedpercent)(this.buffered(), this.duration_); }; /** * turn off the polyfill for `progress` events that was created in * {@link tech#manualprogresson} * stop manually tracking progress events by clearing the interval that was set in * {@link tech#trackprogress}. */ tech.prototype.stoptrackingprogress = function stoptrackingprogress() { this.clearinterval(this.progressinterval); }; /** * polyfill the `timeupdate` event for browsers that don't support it. * * @see {@link tech#trackcurrenttime} */ tech.prototype.manualtimeupdateson = function manualtimeupdateson() { this.manualtimeupdates = true; this.on('play', this.trackcurrenttime); this.on('pause', this.stoptrackingcurrenttime); }; /** * turn off the polyfill for `timeupdate` events that was created in * {@link tech#manualtimeupdateson} */ tech.prototype.manualtimeupdatesoff = function manualtimeupdatesoff() { this.manualtimeupdates = false; this.stoptrackingcurrenttime(); this.off('play', this.trackcurrenttime); this.off('pause', this.stoptrackingcurrenttime); }; /** * sets up an interval function to track current time and trigger `timeupdate` every * 250 milliseconds. * * @listens tech#play * @triggers tech#timeupdate */ tech.prototype.trackcurrenttime = function trackcurrenttime() { if (this.currenttimeinterval) { this.stoptrackingcurrenttime(); } this.currenttimeinterval = this.setinterval(function () { /** * triggered at an interval of 250ms to indicated that time is passing in the video. * * @event tech#timeupdate * @type {eventtarget~event} */ this.trigger({ type: 'timeupdate', target: this, manuallytriggered: true }); // 42 = 24 fps // 250 is what webkit uses // ff uses 15 }, 250); }; /** * stop the interval function created in {@link tech#trackcurrenttime} so that the * `timeupdate` event is no longer triggered. * * @listens {tech#pause} */ tech.prototype.stoptrackingcurrenttime = function stoptrackingcurrenttime() { this.clearinterval(this.currenttimeinterval); // #1002 - if the video ends right before the next timeupdate would happen, // the progress bar won't make it all the way to the end this.trigger({ type: 'timeupdate', target: this, manuallytriggered: true }); }; /** * turn off all event polyfills, clear the `tech`s {@link audiotracklist}, * {@link videotracklist}, and {@link texttracklist}, and dispose of this tech. * * @fires component#dispose */ tech.prototype.dispose = function dispose() { // clear out all tracks because we can't reuse them between techs this.cleartracks(['audio', 'video', 'text']); // turn off any manual progress or timeupdate tracking if (this.manualprogress) { this.manualprogressoff(); } if (this.manualtimeupdates) { this.manualtimeupdatesoff(); } _component.prototype.dispose.call(this); }; /** * clear out a single `tracklist` or an array of `tracklists` given their names. * * > note: techs without source handlers should call this between sources for `video` * & `audio` tracks. you don't want to use them between tracks! * * @param {string[]|string} types * tracklist names to clear, valid names are `video`, `audio`, and * `text`. */ tech.prototype.cleartracks = function cleartracks(types) { var _this2 = this; types = [].concat(types); // clear out all tracks because we can't reuse them between techs types.foreach(function (type) { var list = _this2[type + 'tracks']() || []; var i = list.length; while (i--) { var track = list[i]; if (type === 'text') { _this2.removeremotetexttrack(track); } list.removetrack_(track); } }); }; /** * remove any texttracks added via addremotetexttrack that are * flagged for automatic garbage collection */ tech.prototype.cleanupautotexttracks = function cleanupautotexttracks() { var list = this.autoremotetexttracks_ || []; var i = list.length; while (i--) { var track = list[i]; this.removeremotetexttrack(track); } }; /** * reset the tech, which will removes all sources and reset the internal readystate. * * @abstract */ tech.prototype.reset = function reset() {}; /** * get or set an error on the tech. * * @param {mediaerror} [err] * error to set on the tech * * @return {mediaerror|null} * the current error object on the tech, or null if there isn't one. */ tech.prototype.error = function error(err) { if (err !== undefined) { this.error_ = new _mediaerror2['default'](err); this.trigger('error'); } return this.error_; }; /** * returns the `timerange`s that have been played through for the current source. * * > note: this implementation is incomplete. it does not track the played `timerange`. * it only checks wether the source has played at all or not. * * @return {timerange} * - a single time range if this video has played * - an empty set of ranges if not. */ tech.prototype.played = function played() { if (this.hasstarted_) { return (0, _timeranges.createtimerange)(0, 0); } return (0, _timeranges.createtimerange)(); }; /** * causes a manual time update to occur if {@link tech#manualtimeupdateson} was * previously called. * * @fires tech#timeupdate */ tech.prototype.setcurrenttime = function setcurrenttime() { // improve the accuracy of manual timeupdates if (this.manualtimeupdates) { /** * a manual `timeupdate` event. * * @event tech#timeupdate * @type {eventtarget~event} */ this.trigger({ type: 'timeupdate', target: this, manuallytriggered: true }); } }; /** * turn on listeners for {@link texttracklist} events. this adds * {@link eventtarget~eventlisteners} for `texttrackchange`, `addtrack` and * `removetrack`. * * @fires tech#texttrackchange */ tech.prototype.inittexttracklisteners = function inittexttracklisteners() { var texttracklistchanges = fn.bind(this, function () { /** * triggered when tracks are added or removed on the tech {@link texttracklist} * * @event tech#texttrackchange * @type {eventtarget~event} */ this.trigger('texttrackchange'); }); var tracks = this.texttracks(); if (!tracks) { return; } tracks.addeventlistener('removetrack', texttracklistchanges); tracks.addeventlistener('addtrack', texttracklistchanges); this.on('dispose', fn.bind(this, function () { tracks.removeeventlistener('removetrack', texttracklistchanges); tracks.removeeventlistener('addtrack', texttracklistchanges); })); }; /** * turn on listeners for {@link videotracklist} and {@link {audiotracklist} events. * this adds {@link eventtarget~eventlisteners} for `addtrack`, and `removetrack`. * * @fires tech#audiotrackchange * @fires tech#videotrackchange */ tech.prototype.inittracklisteners = function inittracklisteners() { var _this3 = this; var tracktypes = ['video', 'audio']; tracktypes.foreach(function (type) { /** * triggered when tracks are added or removed on the tech {@link audiotracklist} * * @event tech#audiotrackchange * @type {eventtarget~event} */ /** * triggered when tracks are added or removed on the tech {@link videotracklist} * * @event tech#videotrackchange * @type {eventtarget~event} */ var tracklistchanges = function tracklistchanges() { _this3.trigger(type + 'trackchange'); }; var tracks = _this3[type + 'tracks'](); tracks.addeventlistener('removetrack', tracklistchanges); tracks.addeventlistener('addtrack', tracklistchanges); _this3.on('dispose', function () { tracks.removeeventlistener('removetrack', tracklistchanges); tracks.removeeventlistener('addtrack', tracklistchanges); }); }); }; /** * emulate texttracks using vtt.js if necessary * * @fires tech#vttjsloaded * @fires tech#vttjserror */ tech.prototype.addwebvttscript_ = function addwebvttscript_() { var _this4 = this; if (_window2['default'].webvtt) { return; } // initially, tech.el_ is a child of a dummy-div wait until the component system // signals that the tech is ready at which point tech.el_ is part of the dom // before inserting the webvtt script if (_document2['default'].body.contains(this.el())) { var vtt = _dereq_(105); // load via require if available and vtt.js script location was not passed in // as an option. novtt builds will turn the above require call into an empty object // which will cause this if check to always fail. if (!this.options_['vtt.js'] && (0, _obj.isplain)(vtt) && object.keys(vtt).length > 0) { this.trigger('vttjsloaded'); return; } // load vtt.js via the script location option or the cdn of no location was // passed in var script = _document2['default'].createelement('script'); script.src = this.options_['vtt.js'] || 'https://vjs.zencdn.net/vttjs/0.12.3/vtt.min.js'; script.onload = function () { /** * fired when vtt.js is loaded. * * @event tech#vttjsloaded * @type {eventtarget~event} */ _this4.trigger('vttjsloaded'); }; script.onerror = function () { /** * fired when vtt.js was not loaded due to an error * * @event tech#vttjsloaded * @type {eventtarget~event} */ _this4.trigger('vttjserror'); }; this.on('dispose', function () { script.onload = null; script.onerror = null; }); // but have not loaded yet and we set it to true before the inject so that // we don't overwrite the injected window.webvtt if it loads right away _window2['default'].webvtt = true; this.el().parentnode.appendchild(script); } else { this.ready(this.addwebvttscript_); } }; /** * emulate texttracks * * @method emulatetexttracks */ tech.prototype.emulatetexttracks = function emulatetexttracks() { var _this5 = this; var tracks = this.texttracks(); if (!tracks) { return; } var remotetracks = this.remotetexttracks(); var handleaddtrack = function handleaddtrack(e) { return tracks.addtrack_(e.track); }; var handleremovetrack = function handleremovetrack(e) { return tracks.removetrack_(e.track); }; remotetracks.on('addtrack', handleaddtrack); remotetracks.on('removetrack', handleremovetrack); this.addwebvttscript_(); var updatedisplay = function updatedisplay() { return _this5.trigger('texttrackchange'); }; var texttrackschanges = function texttrackschanges() { updatedisplay(); for (var i = 0; i < tracks.length; i++) { var track = tracks[i]; track.removeeventlistener('cuechange', updatedisplay); if (track.mode === 'showing') { track.addeventlistener('cuechange', updatedisplay); } } }; texttrackschanges(); tracks.addeventlistener('change', texttrackschanges); tracks.addeventlistener('addtrack', texttrackschanges); tracks.addeventlistener('removetrack', texttrackschanges); this.on('dispose', function () { remotetracks.off('addtrack', handleaddtrack); remotetracks.off('removetrack', handleremovetrack); tracks.removeeventlistener('change', texttrackschanges); tracks.removeeventlistener('addtrack', texttrackschanges); tracks.removeeventlistener('removetrack', texttrackschanges); for (var i = 0; i < tracks.length; i++) { var track = tracks[i]; track.removeeventlistener('cuechange', updatedisplay); } }); }; /** * get the `tech`s {@link videotracklist}. * * @return {videotracklist} * the video track list that the tech is currently using. */ tech.prototype.videotracks = function videotracks() { this.videotracks_ = this.videotracks_ || new _videotracklist2['default'](); return this.videotracks_; }; /** * get the `tech`s {@link audiotracklist}. * * @return {audiotracklist} * the audio track list that the tech is currently using. */ tech.prototype.audiotracks = function audiotracks() { this.audiotracks_ = this.audiotracks_ || new _audiotracklist2['default'](); return this.audiotracks_; }; /** * get the `tech`s {@link texttracklist}. * * @return {texttracklist} * the text track list that the tech is currently using. */ tech.prototype.texttracks = function texttracks() { this.texttracks_ = this.texttracks_ || new _texttracklist2['default'](); return this.texttracks_; }; /** * get the `tech`s remote {@link texttracklist}, which is created from elements * that were added to the dom. * * @return {texttracklist} * the remote text track list that the tech is currently using. */ tech.prototype.remotetexttracks = function remotetexttracks() { this.remotetexttracks_ = this.remotetexttracks_ || new _texttracklist2['default'](); return this.remotetexttracks_; }; /** * get the `tech`s {htmltrackelementlist}, which are the elements in the dom that are * being used as texttracks. * * @return {htmltrackelementlist} * the current html track elements that exist for the tech. */ tech.prototype.remotetexttrackels = function remotetexttrackels() { this.remotetexttrackels_ = this.remotetexttrackels_ || new _htmltrackelementlist2['default'](); return this.remotetexttrackels_; }; /** * create and returns a remote {@link texttrack} object. * * @param {string} kind * `texttrack` kind (subtitles, captions, descriptions, chapters, or metadata) * * @param {string} [label] * label to identify the text track * * @param {string} [language] * two letter language abbreviation * * @return {texttrack} * the texttrack that gets created. */ tech.prototype.addtexttrack = function addtexttrack(kind, label, language) { if (!kind) { throw new error('texttrack kind is required but was not provided'); } return createtrackhelper(this, kind, label, language); }; /** * create an emulated texttrack for use by addremotetexttrack * * this is intended to be overridden by classes that inherit from * tech in order to create native or custom texttracks. * * @param {object} options * the object should contain the options to initialize the texttrack with. * * @param {string} [options.kind] * `texttrack` kind (subtitles, captions, descriptions, chapters, or metadata). * * @param {string} [options.label]. * label to identify the text track * * @param {string} [options.language] * two letter language abbreviation. * * @return {htmltrackelement} * the track element that gets created. */ tech.prototype.createremotetexttrack = function createremotetexttrack(options) { var track = (0, _mergeoptions2['default'])(options, { tech: this }); return new _htmltrackelement2['default'](track); }; /** * creates a remote text track object and returns an html track element. * * > note: this can be an emulated {@link htmltrackelement} or a native one. * * @param {object} options * see {@link tech#createremotetexttrack} for more detailed properties. * * @param {boolean} [manualcleanup=true] * - when false: the texttrack will be automatically removed from the video * element whenever the source changes * - when true: the texttrack will have to be cleaned up manually * * @return {htmltrackelement} * an html track element. * * @deprecated the default functionality for this function will be equivalent * to "manualcleanup=false" in the future. the manualcleanup parameter will * also be removed. */ tech.prototype.addremotetexttrack = function addremotetexttrack() { var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var manualcleanup = arguments[1]; var htmltrackelement = this.createremotetexttrack(options); if (manualcleanup !== true && manualcleanup !== false) { // deprecation warning _log2['default'].warn('calling addremotetexttrack without explicitly setting the "manualcleanup" parameter to `true` is deprecated and default to `false` in future version of video.js'); manualcleanup = true; } // store htmltrackelement and texttrack to remote list this.remotetexttrackels().addtrackelement_(htmltrackelement); this.remotetexttracks().addtrack_(htmltrackelement.track); if (manualcleanup !== true) { // create the texttracklist if it doesn't exist this.autoremotetexttracks_.addtrack_(htmltrackelement.track); } return htmltrackelement; }; /** * remove a remote text track from the remote `texttracklist`. * * @param {texttrack} track * `texttrack` to remove from the `texttracklist` */ tech.prototype.removeremotetexttrack = function removeremotetexttrack(track) { var trackelement = this.remotetexttrackels().gettrackelementbytrack_(track); // remove htmltrackelement and texttrack from remote list this.remotetexttrackels().removetrackelement_(trackelement); this.remotetexttracks().removetrack_(track); this.autoremotetexttracks_.removetrack_(track); }; /** * a method to set a poster from a `tech`. * * @abstract */ tech.prototype.setposter = function setposter() {}; /* * check if the tech can support the given mime-type. * * the base tech does not support any type, but source handlers might * overwrite this. * * @param {string} type * the mimetype to check for support * * @return {string} * 'probably', 'maybe', or empty string * * @see [spec]{@link https://developer.mozilla.org/en-us/docs/web/api/htmlmediaelement/canplaytype} * * @abstract */ tech.prototype.canplaytype = function canplaytype() { return ''; }; /* * return whether the argument is a tech or not. * can be passed either a class like `html5` or a instance like `player.tech_` * * @param {object} component * the item to check * * @return {boolean} * whether it is a tech or not * - true if it is a tech * - false if it is not */ tech.istech = function istech(component) { return component.prototype instanceof tech || component instanceof tech || component === tech; }; /** * registers a `tech` into a shared list for videojs. * * @param {string} name * name of the `tech` to register. * * @param {object} tech * the `tech` class to register. */ tech.registertech = function registertech(name, tech) { if (!tech.techs_) { tech.techs_ = {}; } if (!tech.istech(tech)) { throw new error('tech ' + name + ' must be a tech'); } tech.techs_[name] = tech; return tech; }; /** * get a `tech` from the shared list by name. * * @param {string} name * name of the component to get * * @return {tech|undefined} * the `tech` or undefined if there was no tech with the name requsted. */ tech.gettech = function gettech(name) { if (tech.techs_ && tech.techs_[name]) { return tech.techs_[name]; } if (_window2['default'] && _window2['default'].videojs && _window2['default'].videojs[name]) { _log2['default'].warn('the ' + name + ' tech was added to the videojs object when it should be registered using videojs.registertech(name, tech)'); return _window2['default'].videojs[name]; } }; return tech; }(_component2['default']); /** * list of associated text tracks. * * @type {texttracklist} * @private */ tech.prototype.texttracks_; // eslint-disable-line /** * list of associated audio tracks. * * @type {audiotracklist} * @private */ tech.prototype.audiotracks_; // eslint-disable-line /** * list of associated video tracks. * * @type {videotracklist} * @private */ tech.prototype.videotracks_; // eslint-disable-line /** * boolean indicating wether the `tech` supports volume control. * * @type {boolean} * @default */ tech.prototype.featuresvolumecontrol = true; /** * boolean indicating wether the `tech` support fullscreen resize control. * resizing plugins using request fullscreen reloads the plugin * * @type {boolean} * @default */ tech.prototype.featuresfullscreenresize = false; /** * boolean indicating wether the `tech` supports changing the speed at which the video * plays. examples: * - set player to play 2x (twice) as fast * - set player to play 0.5x (half) as fast * * @type {boolean} * @default */ tech.prototype.featuresplaybackrate = false; /** * boolean indicating wether the `tech` supports the `progress` event. this is currently * not triggered by video-js-swf. this will be used to determine if * {@link tech#manualprogresson} should be called. * * @type {boolean} * @default */ tech.prototype.featuresprogressevents = false; /** * boolean indicating wether the `tech` supports the `timeupdate` event. this is currently * not triggered by video-js-swf. this will be used to determine if * {@link tech#manualtimeupdates} should be called. * * @type {boolean} * @default */ tech.prototype.featurestimeupdateevents = false; /** * boolean indicating wether the `tech` supports the native `texttrack`s. * this will help us integrate with native `texttrack`s if the browser supports them. * * @type {boolean} * @default */ tech.prototype.featuresnativetexttracks = false; /** * a functional mixin for techs that want to use the source handler pattern. * source handlers are scripts for handling specific formats. * the source handler pattern is used for adaptive formats (hls, dash) that * manually load video data and feed it into a source buffer (media source extensions) * example: `tech.withsourcehandlers.call(mytech);` * * @param {tech} _tech * the tech to add source handler functions to. * * @mixes tech~sourcehandleradditions */ tech.withsourcehandlers = function (_tech) { /** * register a source handler * * @param {function} handler * the source handler class * * @param {number} [index] * register it at the following index */ _tech.registersourcehandler = function (handler, index) { var handlers = _tech.sourcehandlers; if (!handlers) { handlers = _tech.sourcehandlers = []; } if (index === undefined) { // add to the end of the list index = handlers.length; } handlers.splice(index, 0, handler); }; /** * check if the tech can support the given type. also checks the * techs sourcehandlers. * * @param {string} type * the mimetype to check. * * @return {string} * 'probably', 'maybe', or '' (empty string) */ _tech.canplaytype = function (type) { var handlers = _tech.sourcehandlers || []; var can = void 0; for (var i = 0; i < handlers.length; i++) { can = handlers[i].canplaytype(type); if (can) { return can; } } return ''; }; /** * returns the first source handler that supports the source. * * todo: answer question: should 'probably' be prioritized over 'maybe' * * @param {tech~sourceobject} source * the source object * * @param {object} options * the options passed to the tech * * @return {sourcehandler|null} * the first source handler that supports the source or null if * no sourcehandler supports the source */ _tech.selectsourcehandler = function (source, options) { var handlers = _tech.sourcehandlers || []; var can = void 0; for (var i = 0; i < handlers.length; i++) { can = handlers[i].canhandlesource(source, options); if (can) { return handlers[i]; } } return null; }; /** * check if the tech can support the given source. * * @param {tech~sourceobject} srcobj * the source object * * @param {object} options * the options passed to the tech * * @return {string} * 'probably', 'maybe', or '' (empty string) */ _tech.canplaysource = function (srcobj, options) { var sh = _tech.selectsourcehandler(srcobj, options); if (sh) { return sh.canhandlesource(srcobj, options); } return ''; }; /** * when using a source handler, prefer its implementation of * any function normally provided by the tech. */ var deferrable = ['seekable', 'duration']; /** * a wrapper around {@link tech#seekable} that will call a `sourcehandler`s seekable * function if it exists, with a fallback to the techs seekable function. * * @method _tech.seekable */ /** * a wrapper around {@link tech#duration} that will call a `sourcehandler`s duration * function if it exists, otherwise it will fallback to the techs duration function. * * @method _tech.duration */ deferrable.foreach(function (fnname) { var originalfn = this[fnname]; if (typeof originalfn !== 'function') { return; } this[fnname] = function () { if (this.sourcehandler_ && this.sourcehandler_[fnname]) { return this.sourcehandler_[fnname].apply(this.sourcehandler_, arguments); } return originalfn.apply(this, arguments); }; }, _tech.prototype); /** * create a function for setting the source using a source object * and source handlers. * should never be called unless a source handler was found. * * @param {tech~sourceobject} source * a source object with src and type keys * * @return {tech} * returns itself; this method is chainable */ _tech.prototype.setsource = function (source) { var sh = _tech.selectsourcehandler(source, this.options_); if (!sh) { // fall back to a native source hander when unsupported sources are // deliberately set if (_tech.nativesourcehandler) { sh = _tech.nativesourcehandler; } else { _log2['default'].error('no source hander found for the current source.'); } } // dispose any existing source handler this.disposesourcehandler(); this.off('dispose', this.disposesourcehandler); if (sh !== _tech.nativesourcehandler) { this.currentsource_ = source; // catch if someone replaced the src without calling setsource. // if they do, set currentsource_ to null and dispose our source handler. this.off(this.el_, 'loadstart', _tech.prototype.firstloadstartlistener_); this.off(this.el_, 'loadstart', _tech.prototype.successiveloadstartlistener_); this.one(this.el_, 'loadstart', _tech.prototype.firstloadstartlistener_); } this.sourcehandler_ = sh.handlesource(source, this, this.options_); this.on('dispose', this.disposesourcehandler); return this; }; /** * called once for the first loadstart of a video. * * @listens tech#loadstart */ _tech.prototype.firstloadstartlistener_ = function () { this.one(this.el_, 'loadstart', _tech.prototype.successiveloadstartlistener_); }; // on successive loadstarts when setsource has not been called again /** * called after the first loadstart for a video occurs. * * @listens tech#loadstart */ _tech.prototype.successiveloadstartlistener_ = function () { this.disposesourcehandler(); this.one(this.el_, 'loadstart', _tech.prototype.successiveloadstartlistener_); }; /** * clean up any existing sourcehandlers and listeners when the tech is disposed. * * @listens tech#dispose */ _tech.prototype.disposesourcehandler = function () { // if we have a source and get another one // then we are loading something new // than clear all of our current tracks if (this.currentsource_) { this.cleartracks(['audio', 'video']); this.currentsource_ = null; } // always clean up auto-text tracks this.cleanupautotexttracks(); if (this.sourcehandler_) { this.off(this.el_, 'loadstart', _tech.prototype.firstloadstartlistener_); this.off(this.el_, 'loadstart', _tech.prototype.successiveloadstartlistener_); if (this.sourcehandler_.dispose) { this.sourcehandler_.dispose(); } this.sourcehandler_ = null; } }; }; _component2['default'].registercomponent('tech', tech); // old name for tech // @deprecated _component2['default'].registercomponent('mediatechcontroller', tech); tech.registertech('tech', tech); exports['default'] = tech; },{"105":105,"46":46,"5":5,"63":63,"65":65,"66":66,"70":70,"72":72,"76":76,"79":79,"83":83,"86":86,"87":87,"88":88,"90":90,"94":94,"95":95}],63:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _tracklist = _dereq_(74); var _tracklist2 = _interoprequiredefault(_tracklist); var _browser = _dereq_(78); var browser = _interoprequirewildcard(_browser); var _document = _dereq_(94); var _document2 = _interoprequiredefault(_document); function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file audio-track-list.js */ /** * anywhere we call this function we diverge from the spec * as we only support one enabled audiotrack at a time * * @param {audiotracklist} list * list to work on * * @param {audiotrack} track * the track to skip * * @private */ var disableothers = function disableothers(list, track) { for (var i = 0; i < list.length; i++) { if (track.id === list[i].id) { continue; } // another audio track is enabled, disable it list[i].enabled = false; } }; /** * the current list of {@link audiotrack} for a media file. * * @see [spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#audiotracklist} * @extends tracklist */ var audiotracklist = function (_tracklist) { _inherits(audiotracklist, _tracklist); /** * create an instance of this class. * * @param {audiotrack[]} [tracks=[]] * a list of `audiotrack` to instantiate the list with. */ function audiotracklist() { var _this, _ret; var tracks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; _classcallcheck(this, audiotracklist); var list = void 0; // make sure only 1 track is enabled // sorted from last index to first index for (var i = tracks.length - 1; i >= 0; i--) { if (tracks[i].enabled) { disableothers(tracks, tracks[i]); break; } } // ie8 forces us to implement inheritance ourselves // as it does not support object.defineproperty properly if (browser.is_ie8) { list = _document2['default'].createelement('custom'); for (var prop in _tracklist2['default'].prototype) { if (prop !== 'constructor') { list[prop] = _tracklist2['default'].prototype[prop]; } } for (var _prop in audiotracklist.prototype) { if (_prop !== 'constructor') { list[_prop] = audiotracklist.prototype[_prop]; } } } list = (_this = _possibleconstructorreturn(this, _tracklist.call(this, tracks, list)), _this); list.changing_ = false; return _ret = list, _possibleconstructorreturn(_this, _ret); } /** * add an {@link audiotrack} to the `audiotracklist`. * * @param {audiotrack} track * the audiotrack to add to the list * * @fires track#addtrack * @private */ audiotracklist.prototype.addtrack_ = function addtrack_(track) { var _this2 = this; if (track.enabled) { disableothers(this, track); } _tracklist.prototype.addtrack_.call(this, track); // native tracks don't have this if (!track.addeventlistener) { return; } /** * @listens audiotrack#enabledchange * @fires tracklist#change */ track.addeventlistener('enabledchange', function () { // when we are disabling other tracks (since we don't support // more than one track at a time) we will set changing_ // to true so that we don't trigger additional change events if (_this2.changing_) { return; } _this2.changing_ = true; disableothers(_this2, track); _this2.changing_ = false; _this2.trigger('change'); }); }; /** * add an {@link audiotrack} to the `audiotracklist`. * * @param {audiotrack} track * the audiotrack to add to the list * * @fires track#addtrack */ audiotracklist.prototype.addtrack = function addtrack(track) { this.addtrack_(track); }; /** * remove an {@link audiotrack} from the `audiotracklist`. * * @param {audiotrack} track * the audiotrack to remove from the list * * @fires track#removetrack */ audiotracklist.prototype.removetrack = function removetrack(track) { _tracklist.prototype.removetrack_.call(this, track); }; return audiotracklist; }(_tracklist2['default']); exports['default'] = audiotracklist; },{"74":74,"78":78,"94":94}],64:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _trackenums = _dereq_(73); var _track = _dereq_(75); var _track2 = _interoprequiredefault(_track); var _mergeoptions = _dereq_(87); var _mergeoptions2 = _interoprequiredefault(_mergeoptions); var _browser = _dereq_(78); var browser = _interoprequirewildcard(_browser); function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * a representation of a single `audiotrack`. if it is part of an {@link audiotracklist} * only one `audiotrack` in the list will be enabled at a time. * * @see [spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#audiotrack} * @extends track */ var audiotrack = function (_track) { _inherits(audiotrack, _track); /** * create an instance of this class. * * @param {object} [options={}] * object of option names and values * * @param {audiotrack~kind} [options.kind=''] * a valid audio track kind * * @param {string} [options.id='vjs_track_' + guid.newguid()] * a unique id for this audiotrack. * * @param {string} [options.label=''] * the menu label for this track. * * @param {string} [options.language=''] * a valid two character language code. * * @param {boolean} [options.enabled] * if this track is the one that is currently playing. if this track is part of * an {@link audiotracklist}, only one {@link audiotrack} will be enabled. */ function audiotrack() { var _this, _ret; var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; _classcallcheck(this, audiotrack); var settings = (0, _mergeoptions2['default'])(options, { kind: _trackenums.audiotrackkind[options.kind] || '' }); // on ie8 this will be a document element // for every other browser this will be a normal object var track = (_this = _possibleconstructorreturn(this, _track.call(this, settings)), _this); var enabled = false; if (browser.is_ie8) { for (var prop in audiotrack.prototype) { if (prop !== 'constructor') { track[prop] = audiotrack.prototype[prop]; } } } /** * @member {boolean} enabled * if this `audiotrack` is enabled or not. when setting this will * fire {@link audiotrack#enabledchange} if the state of enabled is changed. * * @fires videotrack#selectedchange */ object.defineproperty(track, 'enabled', { get: function get() { return enabled; }, set: function set(newenabled) { // an invalid or unchanged value if (typeof newenabled !== 'boolean' || newenabled === enabled) { return; } enabled = newenabled; /** * an event that fires when enabled changes on this track. this allows * the audiotracklist that holds this track to act accordingly. * * > note: this is not part of the spec! native tracks will do * this internally without an event. * * @event audiotrack#enabledchange * @type {eventtarget~event} */ this.trigger('enabledchange'); } }); // if the user sets this track to selected then // set selected to that true value otherwise // we keep it false if (settings.enabled) { track.enabled = settings.enabled; } track.loaded_ = true; return _ret = track, _possibleconstructorreturn(_this, _ret); } return audiotrack; }(_track2['default']); exports['default'] = audiotrack; },{"73":73,"75":75,"78":78,"87":87}],65:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _browser = _dereq_(78); var browser = _interoprequirewildcard(_browser); var _document = _dereq_(94); var _document2 = _interoprequiredefault(_document); function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } /** * @file html-track-element-list.js */ /** * the current list of {@link htmltrackelement}s. */ var htmltrackelementlist = function () { /** * create an instance of this class. * * @param {htmltrackelement[]} [tracks=[]] * a list of `htmltrackelement` to instantiate the list with. */ function htmltrackelementlist() { var trackelements = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; _classcallcheck(this, htmltrackelementlist); var list = this; // eslint-disable-line if (browser.is_ie8) { list = _document2['default'].createelement('custom'); for (var prop in htmltrackelementlist.prototype) { if (prop !== 'constructor') { list[prop] = htmltrackelementlist.prototype[prop]; } } } list.trackelements_ = []; /** * @member {number} length * the current number of `track`s in the this trackist. */ object.defineproperty(list, 'length', { get: function get() { return this.trackelements_.length; } }); for (var i = 0, length = trackelements.length; i < length; i++) { list.addtrackelement_(trackelements[i]); } if (browser.is_ie8) { return list; } } /** * add an {@link htmltrackelement} to the `htmltrackelementlist` * * @param {htmltrackelement} trackelement * the track element to add to the list. * * @private */ htmltrackelementlist.prototype.addtrackelement_ = function addtrackelement_(trackelement) { var index = this.trackelements_.length; if (!('' + index in this)) { object.defineproperty(this, index, { get: function get() { return this.trackelements_[index]; } }); } // do not add duplicate elements if (this.trackelements_.indexof(trackelement) === -1) { this.trackelements_.push(trackelement); } }; /** * get an {@link htmltrackelement} from the `htmltrackelementlist` given an * {@link texttrack}. * * @param {texttrack} track * the track associated with a track element. * * @return {htmltrackelement|undefined} * the track element that was found or undefined. * * @private */ htmltrackelementlist.prototype.gettrackelementbytrack_ = function gettrackelementbytrack_(track) { var trackelement_ = void 0; for (var i = 0, length = this.trackelements_.length; i < length; i++) { if (track === this.trackelements_[i].track) { trackelement_ = this.trackelements_[i]; break; } } return trackelement_; }; /** * remove a {@link htmltrackelement} from the `htmltrackelementlist` * * @param {htmltrackelement} trackelement * the track element to remove from the list. * * @private */ htmltrackelementlist.prototype.removetrackelement_ = function removetrackelement_(trackelement) { for (var i = 0, length = this.trackelements_.length; i < length; i++) { if (trackelement === this.trackelements_[i]) { this.trackelements_.splice(i, 1); break; } } }; return htmltrackelementlist; }(); exports['default'] = htmltrackelementlist; },{"78":78,"94":94}],66:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _browser = _dereq_(78); var browser = _interoprequirewildcard(_browser); var _document = _dereq_(94); var _document2 = _interoprequiredefault(_document); var _eventtarget = _dereq_(42); var _eventtarget2 = _interoprequiredefault(_eventtarget); var _texttrack = _dereq_(72); var _texttrack2 = _interoprequiredefault(_texttrack); function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file html-track-element.js */ /** * @typedef {htmltrackelement~readystate} * @enum {number} */ var none = 0; var loading = 1; var loaded = 2; var error = 3; /** * a single track represented in the dom. * * @see [spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#htmltrackelement} * @extends eventtarget */ var htmltrackelement = function (_eventtarget) { _inherits(htmltrackelement, _eventtarget); /** * create an instance of this class. * * @param {object} options={} * object of option names and values * * @param {tech} options.tech * a reference to the tech that owns this htmltrackelement. * * @param {texttrack~kind} [options.kind='subtitles'] * a valid text track kind. * * @param {texttrack~mode} [options.mode='disabled'] * a valid text track mode. * * @param {string} [options.id='vjs_track_' + guid.newguid()] * a unique id for this texttrack. * * @param {string} [options.label=''] * the menu label for this track. * * @param {string} [options.language=''] * a valid two character language code. * * @param {string} [options.srclang=''] * a valid two character language code. an alternative, but deprioritized * vesion of `options.language` * * @param {string} [options.src] * a url to texttrack cues. * * @param {boolean} [options.default] * if this track should default to on or off. */ function htmltrackelement() { var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; _classcallcheck(this, htmltrackelement); var _this = _possibleconstructorreturn(this, _eventtarget.call(this)); var readystate = void 0; var trackelement = _this; // eslint-disable-line if (browser.is_ie8) { trackelement = _document2['default'].createelement('custom'); for (var prop in htmltrackelement.prototype) { if (prop !== 'constructor') { trackelement[prop] = htmltrackelement.prototype[prop]; } } } var track = new _texttrack2['default'](options); trackelement.kind = track.kind; trackelement.src = track.src; trackelement.srclang = track.language; trackelement.label = track.label; trackelement['default'] = track['default']; /** * @member {htmltrackelement~readystate} readystate * the current ready state of the track element. */ object.defineproperty(trackelement, 'readystate', { get: function get() { return readystate; } }); /** * @member {texttrack} track * the underlying texttrack object. */ object.defineproperty(trackelement, 'track', { get: function get() { return track; } }); readystate = none; /** * @listens texttrack#loadeddata * @fires htmltrackelement#load */ track.addeventlistener('loadeddata', function () { readystate = loaded; trackelement.trigger({ type: 'load', target: trackelement }); }); if (browser.is_ie8) { var _ret; return _ret = trackelement, _possibleconstructorreturn(_this, _ret); } return _this; } return htmltrackelement; }(_eventtarget2['default']); htmltrackelement.prototype.allowedevents_ = { load: 'load' }; htmltrackelement.none = none; htmltrackelement.loading = loading; htmltrackelement.loaded = loaded; htmltrackelement.error = error; exports['default'] = htmltrackelement; },{"42":42,"72":72,"78":78,"94":94}],67:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _browser = _dereq_(78); var browser = _interoprequirewildcard(_browser); var _document = _dereq_(94); var _document2 = _interoprequiredefault(_document); function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } /** * @file text-track-cue-list.js */ /** * @typedef {object} texttrackcue * * @property {string} id * the unique id for this text track cue * * @property {number} starttime * the start time for this text track cue * * @property {number} endtime * the end time for this text track cue * * @property {boolean} pauseonexit * pause when the end time is reached if true. * * @see [spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackcue} */ /** * a list of texttrackcues. * * @see [spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackcuelist} */ var texttrackcuelist = function () { /** * create an instance of this class.. * * @param {array} cues * a list of cues to be initialized with */ function texttrackcuelist(cues) { _classcallcheck(this, texttrackcuelist); var list = this; // eslint-disable-line if (browser.is_ie8) { list = _document2['default'].createelement('custom'); for (var prop in texttrackcuelist.prototype) { if (prop !== 'constructor') { list[prop] = texttrackcuelist.prototype[prop]; } } } texttrackcuelist.prototype.setcues_.call(list, cues); /** * @member {number} length * the current number of `texttrackcue`s in the texttrackcuelist. */ object.defineproperty(list, 'length', { get: function get() { return this.length_; } }); if (browser.is_ie8) { return list; } } /** * a setter for cues in this list. creates getters * an an index for the cues. * * @param {array} cues * an array of cues to set * * @private */ texttrackcuelist.prototype.setcues_ = function setcues_(cues) { var oldlength = this.length || 0; var i = 0; var l = cues.length; this.cues_ = cues; this.length_ = cues.length; var defineprop = function defineprop(index) { if (!('' + index in this)) { object.defineproperty(this, '' + index, { get: function get() { return this.cues_[index]; } }); } }; if (oldlength < l) { i = oldlength; for (; i < l; i++) { defineprop.call(this, i); } } }; /** * get a `texttrackcue` that is currently in the `texttrackcuelist` by id. * * @param {string} id * the id of the cue that should be searched for. * * @return {texttrackcue|null} * a single cue or null if none was found. */ texttrackcuelist.prototype.getcuebyid = function getcuebyid(id) { var result = null; for (var i = 0, l = this.length; i < l; i++) { var cue = this[i]; if (cue.id === id) { result = cue; break; } } return result; }; return texttrackcuelist; }(); exports['default'] = texttrackcuelist; },{"78":78,"94":94}],68:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); var _fn = _dereq_(83); var fn = _interoprequirewildcard(_fn); var _window = _dereq_(95); var _window2 = _interoprequiredefault(_window); function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file text-track-display.js */ var darkgray = '#222'; var lightgray = '#ccc'; var fontmap = { monospace: 'monospace', sansserif: 'sans-serif', serif: 'serif', monospacesansserif: '"andale mono", "lucida console", monospace', monospaceserif: '"courier new", monospace', proportionalsansserif: 'sans-serif', proportionalserif: 'serif', casual: '"comic sans ms", impact, fantasy', script: '"monotype corsiva", cursive', smallcaps: '"andale mono", "lucida console", monospace, sans-serif' }; /** * construct an rgba color from a given hex color code. * * @param {number} color * hex number for color, like #f0e. * * @param {number} opacity * value for opacity, 0.0 - 1.0. * * @return {string} * the rgba color that was created, like 'rgba(255, 0, 0, 0.3)'. * * @private */ function constructcolor(color, opacity) { return 'rgba(' + // color looks like "#f0e" parseint(color[1] + color[1], 16) + ',' + parseint(color[2] + color[2], 16) + ',' + parseint(color[3] + color[3], 16) + ',' + opacity + ')'; } /** * try to update the style of a dom element. some style changes will throw an error, * particularly in ie8. those should be noops. * * @param {element} el * the dom element to be styled. * * @param {string} style * the css property on the element that should be styled. * * @param {string} rule * the style rule that should be applied to the property. */ function tryupdatestyle(el, style, rule) { try { el.style[style] = rule; } catch (e) { // satisfies linter. return; } } /** * the component for displaying text track cues. * * @extends component */ var texttrackdisplay = function (_component) { _inherits(texttrackdisplay, _component); /** * creates an instance of this class. * * @param {player} player * the `player` that this class should be attached to. * * @param {object} [options] * the key/value store of player options. * * @param {component~readycallback} [ready] * the function to call when `texttrackdisplay` is ready. */ function texttrackdisplay(player, options, ready) { _classcallcheck(this, texttrackdisplay); var _this = _possibleconstructorreturn(this, _component.call(this, player, options, ready)); player.on('loadstart', fn.bind(_this, _this.toggledisplay)); player.on('texttrackchange', fn.bind(_this, _this.updatedisplay)); // this used to be called during player init, but was causing an error // if a track should show by default and the display hadn't loaded yet. // should probably be moved to an external track loader when we support // tracks that don't need a display. player.ready(fn.bind(_this, function () { if (player.tech_ && player.tech_.featuresnativetexttracks) { this.hide(); return; } player.on('fullscreenchange', fn.bind(this, this.updatedisplay)); var tracks = this.options_.playeroptions.tracks || []; for (var i = 0; i < tracks.length; i++) { this.player_.addremotetexttrack(tracks[i], true); } var modes = { captions: 1, subtitles: 1 }; var tracklist = this.player_.texttracks(); var firstdesc = void 0; var firstcaptions = void 0; if (tracklist) { for (var _i = 0; _i < tracklist.length; _i++) { var track = tracklist[_i]; if (track['default']) { if (track.kind === 'descriptions' && !firstdesc) { firstdesc = track; } else if (track.kind in modes && !firstcaptions) { firstcaptions = track; } } } // we want to show the first default track but captions and subtitles // take precedence over descriptions. // so, display the first default captions or subtitles track // and otherwise the first default descriptions track. if (firstcaptions) { firstcaptions.mode = 'showing'; } else if (firstdesc) { firstdesc.mode = 'showing'; } } })); return _this; } /** * turn display of {@link texttrack}'s from the current state into the other state. * there are only two states: * - 'shown' * - 'hidden' * * @listens player#loadstart */ texttrackdisplay.prototype.toggledisplay = function toggledisplay() { if (this.player_.tech_ && this.player_.tech_.featuresnativetexttracks) { this.hide(); } else { this.show(); } }; /** * create the {@link component}'s dom element. * * @return {element} * the element that was created. */ texttrackdisplay.prototype.createel = function createel() { return _component.prototype.createel.call(this, 'div', { classname: 'vjs-text-track-display' }, { 'aria-live': 'off', 'aria-atomic': 'true' }); }; /** * clear all displayed {@link texttrack}s. */ texttrackdisplay.prototype.cleardisplay = function cleardisplay() { if (typeof _window2['default'].webvtt === 'function') { _window2['default'].webvtt.processcues(_window2['default'], [], this.el_); } }; /** * update the displayed texttrack when a either a {@link player#texttrackchange} or * a {@link player#fullscreenchange} is fired. * * @listens player#texttrackchange * @listens player#fullscreenchange */ texttrackdisplay.prototype.updatedisplay = function updatedisplay() { var tracks = this.player_.texttracks(); this.cleardisplay(); if (!tracks) { return; } // track display prioritization model: if multiple tracks are 'showing', // display the first 'subtitles' or 'captions' track which is 'showing', // otherwise display the first 'descriptions' track which is 'showing' var descriptionstrack = null; var captionssubtitlestrack = null; var i = tracks.length; while (i--) { var track = tracks[i]; if (track.mode === 'showing') { if (track.kind === 'descriptions') { descriptionstrack = track; } else { captionssubtitlestrack = track; } } } if (captionssubtitlestrack) { if (this.getattribute('aria-live') !== 'off') { this.setattribute('aria-live', 'off'); } this.updatefortrack(captionssubtitlestrack); } else if (descriptionstrack) { if (this.getattribute('aria-live') !== 'assertive') { this.setattribute('aria-live', 'assertive'); } this.updatefortrack(descriptionstrack); } }; /** * add an {@link texttrack} to to the {@link tech}s {@link texttracklist}. * * @param {texttrack} track * text track object to be added to the list. */ texttrackdisplay.prototype.updatefortrack = function updatefortrack(track) { if (typeof _window2['default'].webvtt !== 'function' || !track.activecues) { return; } var overrides = this.player_.texttracksettings.getvalues(); var cues = []; for (var _i2 = 0; _i2 < track.activecues.length; _i2++) { cues.push(track.activecues[_i2]); } _window2['default'].webvtt.processcues(_window2['default'], cues, this.el_); var i = cues.length; while (i--) { var cue = cues[i]; if (!cue) { continue; } var cuediv = cue.displaystate; if (overrides.color) { cuediv.firstchild.style.color = overrides.color; } if (overrides.textopacity) { tryupdatestyle(cuediv.firstchild, 'color', constructcolor(overrides.color || '#fff', overrides.textopacity)); } if (overrides.backgroundcolor) { cuediv.firstchild.style.backgroundcolor = overrides.backgroundcolor; } if (overrides.backgroundopacity) { tryupdatestyle(cuediv.firstchild, 'backgroundcolor', constructcolor(overrides.backgroundcolor || '#000', overrides.backgroundopacity)); } if (overrides.windowcolor) { if (overrides.windowopacity) { tryupdatestyle(cuediv, 'backgroundcolor', constructcolor(overrides.windowcolor, overrides.windowopacity)); } else { cuediv.style.backgroundcolor = overrides.windowcolor; } } if (overrides.edgestyle) { if (overrides.edgestyle === 'dropshadow') { cuediv.firstchild.style.textshadow = '2px 2px 3px ' + darkgray + ', 2px 2px 4px ' + darkgray + ', 2px 2px 5px ' + darkgray; } else if (overrides.edgestyle === 'raised') { cuediv.firstchild.style.textshadow = '1px 1px ' + darkgray + ', 2px 2px ' + darkgray + ', 3px 3px ' + darkgray; } else if (overrides.edgestyle === 'depressed') { cuediv.firstchild.style.textshadow = '1px 1px ' + lightgray + ', 0 1px ' + lightgray + ', -1px -1px ' + darkgray + ', 0 -1px ' + darkgray; } else if (overrides.edgestyle === 'uniform') { cuediv.firstchild.style.textshadow = '0 0 4px ' + darkgray + ', 0 0 4px ' + darkgray + ', 0 0 4px ' + darkgray + ', 0 0 4px ' + darkgray; } } if (overrides.fontpercent && overrides.fontpercent !== 1) { var fontsize = _window2['default'].parsefloat(cuediv.style.fontsize); cuediv.style.fontsize = fontsize * overrides.fontpercent + 'px'; cuediv.style.height = 'auto'; cuediv.style.top = 'auto'; cuediv.style.bottom = '2px'; } if (overrides.fontfamily && overrides.fontfamily !== 'default') { if (overrides.fontfamily === 'small-caps') { cuediv.firstchild.style.fontvariant = 'small-caps'; } else { cuediv.firstchild.style.fontfamily = fontmap[overrides.fontfamily]; } } } }; return texttrackdisplay; }(_component2['default']); _component2['default'].registercomponent('texttrackdisplay', texttrackdisplay); exports['default'] = texttrackdisplay; },{"5":5,"83":83,"95":95}],69:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; /** * @file text-track-list-converter.js utilities for capturing text track state and * re-creating tracks based on a capture. * * @module text-track-list-converter */ /** * examine a single {@link texttrack} and return a json-compatible javascript object that * represents the {@link texttrack}'s state. * * @param {texttrack} track * the text track to query. * * @return {object} * a serializable javascript representation of the texttrack. * @private */ var tracktojson_ = function tracktojson_(track) { var ret = ['kind', 'label', 'language', 'id', 'inbandmetadatatrackdispatchtype', 'mode', 'src'].reduce(function (acc, prop, i) { if (track[prop]) { acc[prop] = track[prop]; } return acc; }, { cues: track.cues && array.prototype.map.call(track.cues, function (cue) { return { starttime: cue.starttime, endtime: cue.endtime, text: cue.text, id: cue.id }; }) }); return ret; }; /** * examine a {@link tech} and return a json-compatible javascript array that represents the * state of all {@link texttrack}s currently configured. the return array is compatible with * {@link text-track-list-converter:jsontotexttracks}. * * @param {tech} tech * the tech object to query * * @return {array} * a serializable javascript representation of the {@link tech}s * {@link texttracklist}. */ var texttrackstojson = function texttrackstojson(tech) { var trackels = tech.$$('track'); var trackobjs = array.prototype.map.call(trackels, function (t) { return t.track; }); var tracks = array.prototype.map.call(trackels, function (trackel) { var json = tracktojson_(trackel.track); if (trackel.src) { json.src = trackel.src; } return json; }); return tracks.concat(array.prototype.filter.call(tech.texttracks(), function (track) { return trackobjs.indexof(track) === -1; }).map(tracktojson_)); }; /** * create a set of remote {@link texttrack}s on a {@link tech} based on an array of javascript * object {@link texttrack} representations. * * @param {array} json * an array of `texttrack` representation objects, like those that would be * produced by `texttrackstojson`. * * @param {tech} tech * the `tech` to create the `texttrack`s on. */ var jsontotexttracks = function jsontotexttracks(json, tech) { json.foreach(function (track) { var addedtrack = tech.addremotetexttrack(track).track; if (!track.src && track.cues) { track.cues.foreach(function (cue) { return addedtrack.addcue(cue); }); } }); return tech.texttracks(); }; exports['default'] = { texttrackstojson: texttrackstojson, jsontotexttracks: jsontotexttracks, tracktojson_: tracktojson_ }; },{}],70:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _tracklist = _dereq_(74); var _tracklist2 = _interoprequiredefault(_tracklist); var _fn = _dereq_(83); var fn = _interoprequirewildcard(_fn); var _browser = _dereq_(78); var browser = _interoprequirewildcard(_browser); var _document = _dereq_(94); var _document2 = _interoprequiredefault(_document); function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file text-track-list.js */ /** * the current list of {@link texttrack} for a media file. * * @see [spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#texttracklist} * @extends tracklist */ var texttracklist = function (_tracklist) { _inherits(texttracklist, _tracklist); /** * create an instance of this class. * * @param {texttrack[]} [tracks=[]] * a list of `texttrack` to instantiate the list with. */ function texttracklist() { var _this, _ret; var tracks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; _classcallcheck(this, texttracklist); var list = void 0; // ie8 forces us to implement inheritance ourselves // as it does not support object.defineproperty properly if (browser.is_ie8) { list = _document2['default'].createelement('custom'); for (var prop in _tracklist2['default'].prototype) { if (prop !== 'constructor') { list[prop] = _tracklist2['default'].prototype[prop]; } } for (var _prop in texttracklist.prototype) { if (_prop !== 'constructor') { list[_prop] = texttracklist.prototype[_prop]; } } } list = (_this = _possibleconstructorreturn(this, _tracklist.call(this, tracks, list)), _this); return _ret = list, _possibleconstructorreturn(_this, _ret); } /** * add a {@link texttrack} to the `texttracklist` * * @param {texttrack} track * the text track to add to the list. * * @fires tracklist#addtrack * @private */ texttracklist.prototype.addtrack_ = function addtrack_(track) { _tracklist.prototype.addtrack_.call(this, track); /** * @listens texttrack#modechange * @fires tracklist#change */ track.addeventlistener('modechange', fn.bind(this, function () { this.trigger('change'); })); }; return texttracklist; }(_tracklist2['default']); exports['default'] = texttracklist; },{"74":74,"78":78,"83":83,"94":94}],71:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; var _window = _dereq_(95); var _window2 = _interoprequiredefault(_window); var _component = _dereq_(5); var _component2 = _interoprequiredefault(_component); var _dom = _dereq_(81); var _fn = _dereq_(83); var fn = _interoprequirewildcard(_fn); var _obj = _dereq_(88); var obj = _interoprequirewildcard(_obj); var _log = _dereq_(86); var _log2 = _interoprequiredefault(_log); function _interoprequirewildcard(obj) { if (obj && obj.__esmodule) { return obj; } else { var newobj = {}; if (obj != null) { for (var key in obj) { if (object.prototype.hasownproperty.call(obj, key)) newobj[key] = obj[key]; } } newobj['default'] = obj; return newobj; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } } function _possibleconstructorreturn(self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; } /** * @file text-track-settings.js */ var local_storage_key = 'vjs-text-track-settings'; var color_black = ['#000', 'black']; var color_blue = ['#00f', 'blue']; var color_cyan = ['#0ff', 'cyan']; var color_green = ['#0f0', 'green']; var color_magenta = ['#f0f', 'magenta']; var color_red = ['#f00', 'red']; var color_white = ['#fff', 'white']; var color_yellow = ['#ff0', 'yellow']; var opacity_opaque = ['1', 'opaque']; var opacity_semi = ['0.5', 'semi-transparent']; var opacity_trans = ['0', 'transparent']; // configuration for the various element. var selectconfigs = { backgroundcolor: { selector: '.vjs-bg-color > select', id: 'captions-background-color-%s', label: 'color', options: [color_black, color_white, color_red, color_green, color_blue, color_yellow, color_magenta, color_cyan] }, backgroundopacity: { selector: '.vjs-bg-opacity > select', id: 'captions-background-opacity-%s', label: 'transparency', options: [opacity_opaque, opacity_semi, opacity_trans] }, color: { selector: '.vjs-fg-color > select', id: 'captions-foreground-color-%s', label: 'color', options: [color_white, color_black, color_red, color_green, color_blue, color_yellow, color_magenta, color_cyan] }, edgestyle: { selector: '.vjs-edge-style > select', id: '%s', label: 'text edge style', options: [['none', 'none'], ['raised', 'raised'], ['depressed', 'depressed'], ['uniform', 'uniform'], ['dropshadow', 'dropshadow']] }, fontfamily: { selector: '.vjs-font-family > select', id: 'captions-font-family-%s', label: 'font family', options: [['proportionalsansserif', 'proportional sans-serif'], ['monospacesansserif', 'monospace sans-serif'], ['proportionalserif', 'proportional serif'], ['monospaceserif', 'monospace serif'], ['casual', 'casual'], ['script', 'script'], ['small-caps', 'small caps']] }, fontpercent: { selector: '.vjs-font-percent > select', id: 'captions-font-size-%s', label: 'font size', options: [['0.50', '50%'], ['0.75', '75%'], ['1.00', '100%'], ['1.25', '125%'], ['1.50', '150%'], ['1.75', '175%'], ['2.00', '200%'], ['3.00', '300%'], ['4.00', '400%']], 'default': 2, parser: function parser(v) { return v === '1.00' ? null : number(v); } }, textopacity: { selector: '.vjs-text-opacity > select', id: 'captions-foreground-opacity-%s', label: 'transparency', options: [opacity_opaque, opacity_semi] }, // options for this object are defined below. windowcolor: { selector: '.vjs-window-color > select', id: 'captions-window-color-%s', label: 'color' }, // options for this object are defined below. windowopacity: { selector: '.vjs-window-opacity > select', id: 'captions-window-opacity-%s', label: 'transparency', options: [opacity_trans, opacity_semi, opacity_opaque] } }; selectconfigs.windowcolor.options = selectconfigs.backgroundcolor.options; /** * get the actual value of an option. * * @param {string} value * the value to get * * @param {function} [parser] * optional function to adjust the value. * * @return {mixed} * - will be `undefined` if no value exists * - will be `undefined` if the given value is "none". * - will be the actual value otherwise. * * @private */ function parseoptionvalue(value, parser) { if (parser) { value = parser(value); } if (value && value !== 'none') { return value; } } /** * gets the value of the selected