1
0
mirror of https://github.com/videojs/video.js.git synced 2025-02-16 12:23:54 +02:00

Improved JSDoc comments everywhere for new docs generation

closes #2270
This commit is contained in:
Matt Boles 2015-06-12 11:31:18 -04:00 committed by heff
parent f73f69c66c
commit 77a96bea6f
75 changed files with 2414 additions and 447 deletions

View File

@ -56,6 +56,7 @@ CHANGELOG
* @thijstriemstra added a logged error when a plugin is missing ([view](https://github.com/videojs/video.js/pull/1931))
* @gkatsev fixed the texttrackchange event and text track display for non-native tracks ([view](https://github.com/videojs/video.js/pull/2215))
* @mischizzle fixed event.relatedTarget in Firefox ([view](https://github.com/videojs/video.js/pull/2025))
* @mboles updated JSDoc comments everywhere to prepare for new docs ([view](https://github.com/videojs/video.js/pull/2270))
--------------------

View File

@ -1,6 +1,8 @@
/**
* This code injects the required base styles in the head of the document.
*/
* @file base-styles.js
*
* This code injects the required base styles in the head of the document.
*/
import window from 'global/window';
import document from 'global/document';

View File

@ -1,22 +1,39 @@
/**
* @file big-play-button.js
*/
import Button from './button.js';
import Component from './component.js';
/* Big Play Button
================================================================================ */
/**
* Initial play button. Shows before the video has played. The hiding of the
* big play button is done via CSS and player states.
* @param {Player|Object} player
* @param {Object=} options
* @class
* @constructor
*
* @param {Object} player Main Player
* @param {Object=} options Object of option names and values
* @extends Button
* @class BigPlayButton
*/
class BigPlayButton extends Button {
constructor(player, options) {
super(player, options);
}
/**
* Allow sub components to stack CSS class names
*
* @return {String} The constructed class name
* @method buildCSSClass
*/
buildCSSClass() {
return 'vjs-big-play-button';
}
/**
* Handles click for play
*
* @method handleClick
*/
handleClick() {
this.player_.play();
}

View File

@ -1,3 +1,6 @@
/**
* @file button.js
*/
import Component from './component';
import * as Dom from './utils/dom.js';
import * as Events from './utils/events.js';
@ -5,12 +8,11 @@ import * as Fn from './utils/fn.js';
import document from 'global/document';
import assign from 'object.assign';
/* Button - Base class for all buttons
================================================================================ */
/**
* Base class for all buttons
* @param {Player|Object} player
* @param {Object=} options
*
* @param {Object} player Main Player
* @param {Object=} options Object of option names and values
* @extends Component
* @class Button
*/
@ -27,6 +29,14 @@ class Button extends Component {
this.on('blur', this.handleBlur);
}
/**
* Create the component's DOM element
*
* @param {String=} type Element's node type. e.g. 'div'
* @param {Object=} props An object of element attributes that should be set on the element Tag name
* @return {Element}
* @method createEl
*/
createEl(type='button', props={}) {
// Add standard Aria and Tabindex info
props = assign({
@ -49,6 +59,13 @@ class Button extends Component {
return el;
}
/**
* Controls text - both request and localize
*
* @param {String} text Text for button
* @return {String}
* @method controlText
*/
controlText(text) {
if (!text) return this.controlText_ || 'Need Text';
@ -58,19 +75,37 @@ class Button extends Component {
return this;
}
/**
* Allows sub components to stack CSS class names
*
* @return {String}
* @method buildCSSClass
*/
buildCSSClass() {
return `vjs-control vjs-button ${super.buildCSSClass()}`;
}
// Click - Override with specific functionality for button
/**
* Handle Click - Override with specific functionality for button
*
* @method handleClick
*/
handleClick() {}
// Focus - Add keyboard functionality to element
/**
* Handle Focus - Add keyboard functionality to element
*
* @method handleFocus
*/
handleFocus() {
Events.on(document, 'keydown', Fn.bind(this, this.handleKeyPress));
}
// KeyPress (document level) - Trigger click when keys are pressed
/**
* Handle KeyPress (document level) - Trigger click when keys are pressed
*
* @method handleKeyPress
*/
handleKeyPress(event) {
// Check for space bar (32) or enter (13) keys
if (event.which === 32 || event.which === 13) {
@ -79,7 +114,11 @@ class Button extends Component {
}
}
// Blur - Remove keyboard triggers
/**
* Handle Blur - Remove keyboard triggers
*
* @method handleBlur
*/
handleBlur() {
Events.off(document, 'keydown', Fn.bind(this, this.handleKeyPress));
}

View File

@ -1,6 +1,7 @@
/**
* @fileoverview Player Component - Base class for all UI objects
* @file component.js
*
* Player Component - Base class for all UI objects
*/
import window from 'global/window';
@ -16,31 +17,31 @@ import mergeOptions from './utils/merge-options.js';
/**
* Base UI Component class
*
* Components are embeddable UI objects that are represented by both a
* javascript object and an element in the DOM. They can be children of other
* components, and can have many children themselves.
*
* ```js
* // adding a button to the player
* var button = player.addChild('button');
* button.el(); // -> button element
*
* ```
* ```html
* <div class="video-js">
* <div class="vjs-button">Button</div>
* </div>
*
* ```
* Components are also event emitters.
*
* ```js
* button.on('click', function(){
* console.log('Button Clicked!');
* });
*
* button.trigger('customevent');
* ```
*
* @param {Object} player Main Player
* @param {Object=} options
* @class
* @constructor
* @param {Object=} options Object of option names and values
* @param {Function=} ready Ready callback function
* @class Component
*/
class Component {
@ -105,6 +106,8 @@ class Component {
/**
* Dispose of the component and all child components
*
* @method dispose
*/
dispose() {
this.trigger({ type: 'dispose', bubbles: false });
@ -139,6 +142,7 @@ class Component {
* Return the component's player
*
* @return {Player}
* @method player
*/
player() {
return this.player_;
@ -146,14 +150,12 @@ class Component {
/**
* Deep merge of options objects
*
* Whenever a property is an object on both options objects
* the two properties will be merged using mergeOptions.
*
* This is used for merging options for child components. We
* want it to be easy to override individual options on a child
* component without having to rewrite all the other default options.
*
* ```js
* Parent.prototype.options_ = {
* children: {
* 'childOne': { 'foo': 'bar', 'asdf': 'fdsa' },
@ -170,9 +172,9 @@ class Component {
* }
*
* this.options(newOptions);
*
* ```
* RESULT
*
* ```js
* {
* children: {
* 'childOne': { 'foo': 'baz', 'asdf': 'fdsa', 'abc': '123' },
@ -181,9 +183,11 @@ class Component {
* 'childFour': {}
* }
* }
* ```
*
* @param {Object} obj Object of new option values
* @return {Object} A NEW object of this.options_ and obj merged
* @method options
*/
options(obj) {
log.warn('this.options() has been deprecated and will be moved to the constructor in 6.0');
@ -198,10 +202,12 @@ class Component {
/**
* Get the component's DOM element
*
* ```js
* var domEl = myComponent.el();
* ```
*
* @return {Element}
* @method el
*/
el() {
return this.el_;
@ -213,6 +219,7 @@ class Component {
* @param {String=} tagName Element's node type. e.g. 'div'
* @param {Object=} attributes An object of element attributes that should be set on the element
* @return {Element}
* @method createEl
*/
createEl(tagName, attributes) {
return Dom.createEl(tagName, attributes);
@ -247,6 +254,7 @@ class Component {
* Will either be the same as el() or a new element defined in createEl().
*
* @return {Element}
* @method contentEl
*/
contentEl() {
return this.contentEl_ || this.el_;
@ -254,10 +262,12 @@ class Component {
/**
* Get the component's ID
*
* ```js
* var id = myComponent.id();
* ```
*
* @return {String}
* @method id
*/
id() {
return this.id_;
@ -265,10 +275,12 @@ class Component {
/**
* Get the component's name. The name is often used to reference the component.
*
* ```js
* var name = myComponent.name();
* ```
*
* @return {String}
* @method name
*/
name() {
return this.name_;
@ -276,10 +288,12 @@ class Component {
/**
* Get an array of all child components
*
* ```js
* var kids = myComponent.children();
* ```
*
* @return {Array} The children
* @method children
*/
children() {
return this.children_;
@ -289,6 +303,7 @@ class Component {
* Returns a child component with the provided ID
*
* @return {Component}
* @method getChildById
*/
getChildById(id) {
return this.childIndex_[id];
@ -298,6 +313,7 @@ class Component {
* Returns a child component with the provided name
*
* @return {Component}
* @method getChild
*/
getChild(name) {
return this.childNameIndex_[name];
@ -305,7 +321,7 @@ class Component {
/**
* Adds a child component inside this component
*
* ```js
* myComponent.el();
* // -> <div class='my-component'></div>
* myComponent.children();
@ -314,9 +330,9 @@ class Component {
* var myButton = myComponent.addChild('MyButton');
* // -> <div class='my-component'><div class="my-button">myButton<div></div>
* // -> myButton === myComonent.children()[0];
*
* ```
* Pass in options for child constructors and options for children of the child
*
* ```js
* var myButton = myComponent.addChild('MyButton', {
* text: 'Press Me',
* children: {
@ -325,11 +341,12 @@ class Component {
* }
* }
* });
* ```
*
* @param {String|Component} child The class name or instance of a child to add
* @param {Object=} options Options, including options to be passed to children of the child.
* @return {Component} The child component (created by this process if a string was used)
* @suppress {accessControls|checkRegExp|checkTypes|checkVars|const|constantProperty|deprecated|duplicate|es5Strict|fileoverviewTags|globalThis|invalidCasts|missingProperties|nonStandardJsDocs|strictModuleDepCheck|undefinedNames|undefinedVars|unknownDefines|uselessCode|visibility}
* @method addChild
*/
addChild(child, options={}) {
let component;
@ -397,6 +414,7 @@ class Component {
* child component's element from this component's element
*
* @param {Component} component Component to remove
* @method removeChild
*/
removeChild(component) {
if (typeof component === 'string') {
@ -433,7 +451,7 @@ class Component {
/**
* Add and initialize default child components from options
*
* ```js
* // when an instance of MyComponent is created, all children in options
* // will be added to the instance by their name strings and options
* MyComponent.prototype.options_.children = {
@ -441,8 +459,9 @@ class Component {
* myChildOption: true
* }
* }
*
* ```
* // Or when creating the component
* ```js
* var myComp = new MyComponent(player, {
* children: {
* myChildComponent: {
@ -450,10 +469,10 @@ class Component {
* }
* }
* });
*
* ```
* The children option can also be an Array of child names or
* child options objects (that also include a 'name' key).
*
* ```js
* var myComp = new MyComponent(player, {
* children: [
* 'button',
@ -463,7 +482,9 @@ class Component {
* }
* ]
* });
* ```
*
* @method initChildren
*/
initChildren() {
let children = this.options_.children;
@ -528,6 +549,7 @@ class Component {
* Allows sub components to stack CSS class names
*
* @return {String} The constructed class name
* @method buildCSSClass
*/
buildCSSClass() {
// Child classes can include a function that does:
@ -537,26 +559,24 @@ class Component {
/**
* Add an event listener to this component's element
*
* ```js
* var myFunc = function(){
* var myComponent = this;
* // Do something when the event is fired
* };
*
* myComponent.on('eventType', myFunc);
*
* ```
* The context of myFunc will be myComponent unless previously bound.
*
* Alternatively, you can add a listener to another element or component.
*
* ```js
* myComponent.on(otherElement, 'eventName', myFunc);
* myComponent.on(otherComponent, 'eventName', myFunc);
*
* ```
* The benefit of using this over `VjsEvents.on(otherElement, 'eventName', myFunc)`
* and `otherComponent.on('eventName', myFunc)` is that this way the listeners
* will be automatically cleaned up when either component is disposed.
* It will also bind myComponent as the context of myFunc.
*
* **NOTE**: When using this on elements in the page other than window
* and document (both permanent), if you remove the element from the DOM
* you need to call `myComponent.trigger(el, 'dispose')` on it to clean up
@ -565,7 +585,8 @@ class Component {
* @param {String|Component} first The event type or other component
* @param {Function|String} second The event handler or event type
* @param {Function} third The event handler
* @return {Component} self
* @return {Component}
* @method on
*/
on(first, second, third) {
if (typeof first === 'string' || Array.isArray(first)) {
@ -613,23 +634,24 @@ class Component {
/**
* Remove an event listener from this component's element
*
* ```js
* myComponent.off('eventType', myFunc);
*
* ```
* If myFunc is excluded, ALL listeners for the event type will be removed.
* If eventType is excluded, ALL listeners will be removed from the component.
*
* Alternatively you can use `off` to remove listeners that were added to other
* elements or components using `myComponent.on(otherComponent...`.
* In this case both the event type and listener function are REQUIRED.
*
* ```js
* myComponent.off(otherElement, 'eventType', myFunc);
* myComponent.off(otherComponent, 'eventType', myFunc);
* ```
*
* @param {String=|Component} first The event type or other component
* @param {Function=|String} second The listener function or event type
* @param {Function=} third The listener for other component
* @return {Component}
* @method off
*/
off(first, second, third) {
if (!first || typeof first === 'string' || Array.isArray(first)) {
@ -660,19 +682,21 @@ class Component {
/**
* Add an event listener to be triggered only once and then removed
*
* ```js
* myComponent.one('eventName', myFunc);
*
* ```
* Alternatively you can add a listener to another element or component
* that will be triggered only once.
*
* ```js
* myComponent.one(otherElement, 'eventName', myFunc);
* myComponent.one(otherComponent, 'eventName', myFunc);
* ```
*
* @param {String|Component} first The event type or other component
* @param {Function|String} second The listener function or event type
* @param {Function=} third The listener function for other component
* @return {Component}
* @method one
*/
one(first, second, third) {
if (typeof first === 'string' || Array.isArray(first)) {
@ -698,15 +722,17 @@ class Component {
/**
* Trigger an event on an element
*
* ```js
* myComponent.trigger('eventName');
* myComponent.trigger({'type':'eventName'});
* myComponent.trigger('eventName', {data: 'some data'});
* myComponent.trigger({'type':'eventName'}, {data: 'some data'});
* ```
*
* @param {Event|Object|String} event A string (the type) or an event object with a type attribute
* @param {Object} [hash] data hash to pass along with the event
* @return {Component} self
* @method trigger
*/
trigger(event, hash) {
Events.trigger(this.el_, event, hash);
@ -714,13 +740,13 @@ class Component {
}
/**
* Bind a listener to the component's ready state
*
* Bind a listener to the component's ready state.
* Different from event listeners in that if the ready event has already happened
* it will trigger the function immediately.
*
* @param {Function} fn Ready listener
* @return {Component}
* @method ready
*/
ready(fn) {
if (fn) {
@ -739,6 +765,7 @@ class Component {
* Trigger the ready listeners
*
* @return {Component}
* @method triggerReady
*/
triggerReady() {
this.isReady_ = true;
@ -766,6 +793,7 @@ class Component {
*
* @param {String} classToCheck Classname to check
* @return {Component}
* @method hasClass
*/
hasClass(classToCheck) {
return Dom.hasElClass(this.el_, classToCheck);
@ -776,6 +804,7 @@ class Component {
*
* @param {String} classToAdd Classname to add
* @return {Component}
* @method addClass
*/
addClass(classToAdd) {
Dom.addElClass(this.el_, classToAdd);
@ -783,10 +812,11 @@ class Component {
}
/**
* Remove a CSS class name from the component's element
* Remove and return a CSS class name from the component's element
*
* @param {String} classToRemove Classname to remove
* @return {Component}
* @method removeClass
*/
removeClass(classToRemove) {
Dom.removeElClass(this.el_, classToRemove);
@ -797,6 +827,7 @@ class Component {
* Show the component element if hidden
*
* @return {Component}
* @method show
*/
show() {
this.removeClass('vjs-hidden');
@ -807,6 +838,7 @@ class Component {
* Hide the component element if currently showing
*
* @return {Component}
* @method hide
*/
hide() {
this.addClass('vjs-hidden');
@ -819,6 +851,7 @@ class Component {
*
* @return {Component}
* @private
* @method lockShowing
*/
lockShowing() {
this.addClass('vjs-lock-showing');
@ -831,6 +864,7 @@ class Component {
*
* @return {Component}
* @private
* @method unlockShowing
*/
unlockShowing() {
this.removeClass('vjs-lock-showing');
@ -839,7 +873,6 @@ class Component {
/**
* Set or get the width of the component (CSS values)
*
* Setting the video tag dimension values only works with values in pixels.
* Percent values will not work.
* Some percents can be used, but width()/height() will return the number + %,
@ -849,6 +882,7 @@ class Component {
* @param {Boolean} skipListeners Skip the 'resize' event trigger
* @return {Component} This component, when setting the width
* @return {Number|String} The width, when getting
* @method width
*/
width(num, skipListeners) {
return this.dimension('width', num, skipListeners);
@ -856,7 +890,6 @@ class Component {
/**
* Get or set the height of the component (CSS values)
*
* Setting the video tag dimension values only works with values in pixels.
* Percent values will not work.
* Some percents can be used, but width()/height() will return the number + %,
@ -866,6 +899,7 @@ class Component {
* @param {Boolean=} skipListeners Skip the resize event trigger
* @return {Component} This component, when setting the height
* @return {Number|String} The height, when getting
* @method height
*/
height(num, skipListeners) {
return this.dimension('height', num, skipListeners);
@ -874,9 +908,10 @@ class Component {
/**
* Set both width and height at the same time
*
* @param {Number|String} width
* @param {Number|String} height
* @param {Number|String} width Width of player
* @param {Number|String} height Height of player
* @return {Component} The component
* @method dimensions
*/
dimensions(width, height) {
// Skip resize listeners on width for optimization
@ -885,10 +920,8 @@ class Component {
/**
* Get or set width or height
*
* This is the shared code for the width() and height() methods.
* All for an integer, integer + 'px' or integer + '%';
*
* Known issue: Hidden elements officially have a width of 0. We're defaulting
* to the style.width value and falling back to computedStyle which has the
* hidden element issue. Info, but probably not an efficient fix:
@ -900,6 +933,7 @@ class Component {
* @return {Component} The component if a dimension was set
* @return {Number|String} The dimension if nothing was set
* @private
* @method dimension
*/
dimension(widthOrHeight, num, skipListeners) {
if (num !== undefined) {
@ -949,13 +983,13 @@ class Component {
/**
* Emit 'tap' events when touch events are supported
*
* This is used to support toggling the controls through a tap on the video.
*
* We're requiring them to be enabled because otherwise every component would
* have this extra overhead unnecessarily, on mobile devices where extra
* overhead is especially bad.
*
* @private
* @method emitTapEvents
*/
emitTapEvents() {
// Track the start time so we can determine how long the touch lasted
@ -992,7 +1026,7 @@ class Component {
// So, if we moved only a small distance, this could still be a tap
const xdiff = event.touches[0].pageX - firstTouch.pageX;
const ydiff = event.touches[0].pageY - firstTouch.pageY;
const touchDistance = Math.sqrt(xdiff * xdiff + ydiff * ydiff);
const touchDistance = Math.sqrt(xdiff * xdiff + ydiff * ydiff);
if (touchDistance > tapMovementThreshold) {
couldBeTap = false;
@ -1032,12 +1066,10 @@ class Component {
/**
* Report user touch activity when touch events occur
*
* User activity is used to determine when controls should show/hide. It's
* relatively 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. We can't rely on touch events at the
* player level, because a tap (touchstart + touchend) on the video itself on
* mobile devices is meant to turn controls off (and on). User activity is
@ -1045,13 +1077,13 @@ class Component {
* 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)
*
* Also a touchmove, touch+hold, and anything other than a tap is not supposed
* to turn the controls back on on a mobile device.
*
* Here we're setting the default component behavior to report user activity
* whenever touch events happen, and this can be turned off by components that
* want touch events to act differently.
*
* @method enableTouchActivity
*/
enableTouchActivity() {
// Don't continue if the root player doesn't support reporting user activity
@ -1087,9 +1119,11 @@ class Component {
/**
* Creates timeout and sets up disposal automatically.
*
* @param {Function} fn The function to run after the timeout.
* @param {Number} timeout Number of ms to delay before executing specified function.
* @return {Number} Returns the timeout ID
* @method setTimeout
*/
setTimeout(fn, timeout) {
fn = Fn.bind(this, fn);
@ -1110,8 +1144,10 @@ class Component {
/**
* Clears a timeout and removes the associated dispose listener
*
* @param {Number} timeoutId The id of the timeout to clear
* @return {Number} Returns the timeout ID
* @method clearTimeout
*/
clearTimeout(timeoutId) {
window.clearTimeout(timeoutId);
@ -1127,9 +1163,11 @@ class Component {
/**
* Creates an interval and sets up disposal automatically.
*
* @param {Function} fn The function to run every N seconds.
* @param {Number} interval Number of ms to delay before executing specified function.
* @return {Number} Returns the interval ID
* @method setInterval
*/
setInterval(fn, interval) {
fn = Fn.bind(this, fn);
@ -1149,8 +1187,10 @@ class Component {
/**
* Clears an interval and removes the associated dispose listener
*
* @param {Number} intervalId The id of the interval to clear
* @return {Number} Returns the interval ID
* @method clearInterval
*/
clearInterval(intervalId) {
window.clearInterval(intervalId);
@ -1164,6 +1204,14 @@ class Component {
return intervalId;
}
/**
* Registers a component
*
* @param {String} name Name of the component to register
* @param {Object} comp The component to register
* @static
* @method registerComponent
*/
static registerComponent(name, comp) {
if (!Component.components_) {
Component.components_ = {};
@ -1173,6 +1221,14 @@ class Component {
return comp;
}
/**
* Gets a component by name
*
* @param {String} name Name of the component to get
* @return {Component}
* @static
* @method getComponent
*/
static getComponent(name) {
if (Component.components_ && Component.components_[name]) {
return Component.components_[name];
@ -1184,6 +1240,14 @@ class Component {
}
}
/**
* Sets up the constructor using the supplied init method
* or uses the init of the parent object
*
* @param {Object} props An object of properties
* @static
* @method extend
*/
static extend(props) {
props = props || {};
// Set up the constructor using the supplied init method

View File

@ -1,3 +1,6 @@
/**
* @file control-bar.js
*/
import Component from '../component.js';
// Required children
@ -20,13 +23,18 @@ import CustomControlSpacer from './spacer-controls/custom-control-spacer.js';
/**
* Container of main controls
* @param {Player|Object} player
* @param {Object=} options
* @class
* @constructor
*
* @extends Component
* @class ControlBar
*/
class ControlBar extends Component {
/**
* Create the component's DOM element
*
* @return {Element}
* @method createEl
*/
createEl() {
return super.createEl('div', {
className: 'vjs-control-bar'

View File

@ -1,19 +1,32 @@
/**
* @file fullscreen-toggle.js
*/
import Button from '../button.js';
import Component from '../component.js';
/**
* Toggle fullscreen video
* @param {Player|Object} player
* @param {Object=} options
* @class
* @extends vjs.Button
*
* @extends Button
* @class FullscreenToggle
*/
class FullscreenToggle extends Button {
/**
* Allow sub components to stack CSS class names
*
* @return {String} The constructed class name
* @method buildCSSClass
*/
buildCSSClass() {
return `vjs-fullscreen-control ${super.buildCSSClass()}`;
}
/**
* Handles click for full screen
*
* @method handleClick
*/
handleClick() {
if (!this.player_.isFullscreen()) {
this.player_.requestFullscreen();

View File

@ -1,15 +1,24 @@
/**
* @file live-display.js
*/
import Component from '../component';
import * as Dom from '../utils/dom.js';
/**
* Displays the live indicator
* TODO - Future make it click to snap to live
* @param {Player|Object} player
* @param {Object=} options
* @constructor
*
* @extends Component
* @class LiveDisplay
*/
class LiveDisplay extends Component {
/**
* Create the component's DOM element
*
* @return {Element}
* @method createEl
*/
createEl() {
var el = super.createEl('div', {
className: 'vjs-live-control vjs-control'

View File

@ -1,13 +1,17 @@
/**
* @file mute-toggle.js
*/
import Button from '../button';
import Component from '../component';
import * as Dom from '../utils/dom.js';
/**
* A button component for muting the audio
* A button component for muting the audio
*
* @param {Player|Object} player
* @param {Object=} options
* @constructor
* @extends Button
* @class MuteToggle
*/
class MuteToggle extends Button {
@ -30,14 +34,30 @@ class MuteToggle extends Button {
});
}
/**
* Allow sub components to stack CSS class names
*
* @return {String} The constructed class name
* @method buildCSSClass
*/
buildCSSClass() {
return `vjs-mute-control ${super.buildCSSClass()}`;
}
/**
* Handle click on mute
*
* @method handleClick
*/
handleClick() {
this.player_.muted( this.player_.muted() ? false : true );
}
/**
* Update volume
*
* @method update
*/
update() {
var vol = this.player_.volume(),
level = 3;

View File

@ -1,12 +1,16 @@
/**
* @file play-toggle.js
*/
import Button from '../button.js';
import Component from '../component.js';
/**
* Button to toggle between play and pause
*
* @param {Player|Object} player
* @param {Object=} options
* @class
* @constructor
* @extends Button
* @class PlayToggle
*/
class PlayToggle extends Button {
@ -17,11 +21,21 @@ class PlayToggle extends Button {
this.on(player, 'pause', this.handlePause);
}
/**
* Allow sub components to stack CSS class names
*
* @return {String} The constructed class name
* @method buildCSSClass
*/
buildCSSClass() {
return `vjs-play-control ${super.buildCSSClass()}`;
}
// handleClick - Toggle between play and pause
/**
* Handle click to toggle between play and pause
*
* @method handleClick
*/
handleClick() {
if (this.player_.paused()) {
this.player_.play();
@ -30,14 +44,22 @@ class PlayToggle extends Button {
}
}
// handlePlay - Add the vjs-playing class to the element so it can change appearance
/**
* Add the vjs-playing class to the element so it can change appearance
*
* @method handlePlay
*/
handlePlay() {
this.removeClass('vjs-paused');
this.addClass('vjs-playing');
this.controlText('Pause'); // change the button text to "Pause"
}
// handlePause - Add the vjs-paused class to the element so it can change appearance
/**
* Add the vjs-paused class to the element so it can change appearance
*
* @method handlePause
*/
handlePause() {
this.removeClass('vjs-playing');
this.addClass('vjs-paused');

View File

@ -1,3 +1,6 @@
/**
* @file playback-rate-menu-button.js
*/
import MenuButton from '../../menu/menu-button.js';
import Menu from '../../menu/menu.js';
import PlaybackRateMenuItem from './playback-rate-menu-item.js';
@ -9,7 +12,8 @@ import * as Dom from '../../utils/dom.js';
*
* @param {Player|Object} player
* @param {Object=} options
* @constructor
* @extends MenuButton
* @class PlaybackRateMenuButton
*/
class PlaybackRateMenuButton extends MenuButton {
@ -23,6 +27,12 @@ class PlaybackRateMenuButton extends MenuButton {
this.on(player, 'ratechange', this.updateLabel);
}
/**
* Create the component's DOM element
*
* @return {Element}
* @method createEl
*/
createEl() {
let el = super.createEl();
@ -36,11 +46,22 @@ class PlaybackRateMenuButton extends MenuButton {
return el;
}
/**
* Allow sub components to stack CSS class names
*
* @return {String} The constructed class name
* @method buildCSSClass
*/
buildCSSClass() {
return `vjs-playback-rate ${super.buildCSSClass()}`;
}
// Menu creation
/**
* Create the playback rate menu
*
* @return {Menu} Menu object populated with items
* @method createMenu
*/
createMenu() {
let menu = new Menu(this.player());
let rates = this.playbackRates();
@ -56,11 +77,21 @@ class PlaybackRateMenuButton extends MenuButton {
return menu;
}
/**
* Updates ARIA accessibility attributes
*
* @method updateARIAAttributes
*/
updateARIAAttributes() {
// Current playback rate
this.el().setAttribute('aria-valuenow', this.player().playbackRate());
}
/**
* Handle menu item click
*
* @method handleClick
*/
handleClick() {
// select next rate option
let currentRate = this.player().playbackRate();
@ -77,10 +108,22 @@ class PlaybackRateMenuButton extends MenuButton {
this.player().playbackRate(newRate);
}
/**
* Get possible playback rates
*
* @return {Array} Possible playback rates
* @method playbackRates
*/
playbackRates() {
return this.options_['playbackRates'] || (this.options_.playerOptions && this.options_.playerOptions['playbackRates']);
}
/**
* Get supported playback rates
*
* @return {Array} Supported playback rates
* @method playbackRateSupported
*/
playbackRateSupported() {
return this.player().tech
&& this.player().tech['featuresPlaybackRate']
@ -91,6 +134,8 @@ class PlaybackRateMenuButton extends MenuButton {
/**
* Hide playback rate controls when they're no playback rate options to select
*
* @method updateVisibility
*/
updateVisibility() {
if (this.playbackRateSupported()) {
@ -102,6 +147,8 @@ class PlaybackRateMenuButton extends MenuButton {
/**
* Update button label when rate changed
*
* @method updateLabel
*/
updateLabel() {
if (this.playbackRateSupported()) {

View File

@ -1,10 +1,16 @@
/**
* @file playback-rate-menu-item.js
*/
import MenuItem from '../../menu/menu-item.js';
import Component from '../../component.js';
/**
* The specific menu item type for selecting a playback rate
*
* @constructor
* @param {Player|Object} player
* @param {Object=} options
* @extends MenuItem
* @class PlaybackRateMenuItem
*/
class PlaybackRateMenuItem extends MenuItem {
@ -23,11 +29,21 @@ class PlaybackRateMenuItem extends MenuItem {
this.on(player, 'ratechange', this.update);
}
/**
* Handle click on menu item
*
* @method handleClick
*/
handleClick() {
super.handleClick();
this.player().playbackRate(this.rate);
}
/**
* Update playback rate with selected rate
*
* @method update
*/
update() {
this.selected(this.player().playbackRate() === this.rate);
}

View File

@ -1,3 +1,6 @@
/**
* @file load-progress-bar.js
*/
import Component from '../../component.js';
import * as Dom from '../../utils/dom.js';
@ -6,7 +9,8 @@ import * as Dom from '../../utils/dom.js';
*
* @param {Player|Object} player
* @param {Object=} options
* @constructor
* @extends Component
* @class LoadProgressBar
*/
class LoadProgressBar extends Component {
@ -15,6 +19,12 @@ class LoadProgressBar extends Component {
this.on(player, 'progress', this.update);
}
/**
* Create the component's DOM element
*
* @return {Element}
* @method createEl
*/
createEl() {
return super.createEl('div', {
className: 'vjs-load-progress',
@ -22,6 +32,11 @@ class LoadProgressBar extends Component {
});
}
/**
* Update progress bar
*
* @method update
*/
update() {
let buffered = this.player_.buffered();
let duration = this.player_.duration();

View File

@ -1,3 +1,6 @@
/**
* @file play-progress-bar.js
*/
import Component from '../../component.js';
/**
@ -5,10 +8,17 @@ import Component from '../../component.js';
*
* @param {Player|Object} player
* @param {Object=} options
* @constructor
* @extends Component
* @class PlayProgressBar
*/
class PlayProgressBar extends Component {
/**
* Create the component's DOM element
*
* @return {Element}
* @method createEl
*/
createEl() {
return super.createEl('div', {
className: 'vjs-play-progress',

View File

@ -1,3 +1,6 @@
/**
* @file progress-control.js
*/
import Component from '../../component.js';
import SeekBar from './seek-bar.js';
@ -7,9 +10,17 @@ import SeekBar from './seek-bar.js';
*
* @param {Player|Object} player
* @param {Object=} options
* @constructor
* @extends Component
* @class ProgressControl
*/
class ProgressControl extends Component {
/**
* Create the component's DOM element
*
* @return {Element}
* @method createEl
*/
createEl() {
return super.createEl('div', {
className: 'vjs-progress-control vjs-control'

View File

@ -1,3 +1,6 @@
/**
* @file seek-bar.js
*/
import Slider from '../../slider/slider.js';
import Component from '../../component.js';
import LoadProgressBar from './load-progress-bar.js';
@ -11,7 +14,8 @@ import roundFloat from '../../utils/round-float.js';
*
* @param {Player|Object} player
* @param {Object=} options
* @constructor
* @extends Slider
* @class SeekBar
*/
class SeekBar extends Slider {
@ -21,6 +25,12 @@ class SeekBar extends Slider {
player.ready(Fn.bind(this, this.updateARIAAttributes));
}
/**
* Create the component's DOM element
*
* @return {Element}
* @method createEl
*/
createEl() {
return super.createEl('div', {
className: 'vjs-progress-holder',
@ -28,6 +38,11 @@ class SeekBar extends Slider {
});
}
/**
* Update ARIA accessibility attributes
*
* @method updateARIAAttributes
*/
updateARIAAttributes() {
// Allows for smooth scrubbing, when player can't keep up.
let time = (this.player_.scrubbing()) ? this.player_.getCache().currentTime : this.player_.currentTime();
@ -35,11 +50,22 @@ class SeekBar extends Slider {
this.el_.setAttribute('aria-valuetext', formatTime(time, this.player_.duration())); // human readable value of progress bar (time complete)
}
/**
* Get percentage of video played
*
* @return {Number} Percentage played
* @method getPercent
*/
getPercent() {
let percent = this.player_.currentTime() / this.player_.duration();
return percent >= 1 ? 1 : percent;
}
/**
* Handle mouse down on seek bar
*
* @method handleMouseDown
*/
handleMouseDown(event) {
super.handleMouseDown(event);
@ -49,6 +75,11 @@ class SeekBar extends Slider {
this.player_.pause();
}
/**
* Handle mouse move on seek bar
*
* @method handleMouseMove
*/
handleMouseMove(event) {
let newTime = this.calculateDistance(event) * this.player_.duration();
@ -59,6 +90,11 @@ class SeekBar extends Slider {
this.player_.currentTime(newTime);
}
/**
* Handle mouse up on seek bar
*
* @method handleMouseUp
*/
handleMouseUp(event) {
super.handleMouseUp(event);
@ -68,10 +104,20 @@ class SeekBar extends Slider {
}
}
/**
* Move more quickly fast forward for keyboard-only users
*
* @method stepForward
*/
stepForward() {
this.player_.currentTime(this.player_.currentTime() + 5); // more quickly fast forward for keyboard-only users
}
/**
* Move more quickly rewind for keyboard-only users
*
* @method stepBack
*/
stepBack() {
this.player_.currentTime(this.player_.currentTime() - 5); // more quickly rewind for keyboard-only users
}

View File

@ -1,17 +1,33 @@
/**
* @file custom-control-spacer.js
*/
import Spacer from './spacer.js';
import Component from '../../component.js';
/**
* Spacer specifically meant to be used as an insertion point for new plugins, etc.
*
* @param {Player|Object} player
* @param {Obect=} options
* @extends Spacer
* @class CustomControlSpacer
*/
class CustomControlSpacer extends Spacer {
/**
* Allow sub components to stack CSS class names
*
* @return {String} The constructed class name
* @method buildCSSClass
*/
buildCSSClass() {
return `vjs-custom-control-spacer ${super.buildCSSClass()}`;
}
/**
* Create the component's DOM element
*
* @return {Element}
* @method createEl
*/
createEl() {
return super.createEl({
className: this.buildCSSClass()

View File

@ -1,17 +1,34 @@
/**
* @file spacer.js
*/
import Component from '../../component.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.
*
* @param {Player|Object} player
* @param {Object=} options
* @extends Component
* @class Spacer
*/
class Spacer extends Component {
/**
* Allow sub components to stack CSS class names
*
* @return {String} The constructed class name
* @method buildCSSClass
*/
buildCSSClass() {
return `vjs-spacer ${super.buildCSSClass()}`;
}
/**
* Create the component's DOM element
*
* @param {Object} props An object of properties
* @return {Element}
* @method createEl
*/
createEl(props) {
return super.createEl('div', {
className: this.buildCSSClass()

View File

@ -1,7 +1,18 @@
/**
* @file caption-settings-menu-item.js
*/
import TextTrackMenuItem from './text-track-menu-item.js';
import Component from '../../component.js';
class CaptionSettingsMenuItem extends TextTrackMenuItem {
/**
* The menu item for caption track settings menu
*
* @param {Player|Object} player
* @param {Object=} options
* @extends TextTrackMenuItem
* @class CaptionSettingsMenuItem
*/
class CaptionSettingsMenuItem extends TextTrackMenuItem {
constructor(player, options) {
options['track'] = {
@ -16,6 +27,11 @@ class CaptionSettingsMenuItem extends TextTrackMenuItem {
this.addClass('vjs-texttrack-settings');
}
/**
* Handle click on menu item
*
* @method handleClick
*/
handleClick() {
this.player().getChild('textTrackSettings').show();
}

View File

@ -1,3 +1,6 @@
/**
* @file captions-button.js
*/
import TextTrackButton from './text-track-button.js';
import Component from '../../component.js';
import CaptionSettingsMenuItem from './caption-settings-menu-item.js';
@ -5,7 +8,11 @@ import CaptionSettingsMenuItem from './caption-settings-menu-item.js';
/**
* The button component for toggling and selecting captions
*
* @constructor
* @param {Object} player Player object
* @param {Object=} options Object of option names and values
* @param {Function=} ready Ready callback function
* @extends TextTrackButton
* @class CaptionsButton
*/
class CaptionsButton extends TextTrackButton {
@ -14,10 +21,21 @@ class CaptionsButton extends TextTrackButton {
this.el_.setAttribute('aria-label','Captions Menu');
}
/**
* Allow sub components to stack CSS class names
*
* @return {String} The constructed class name
* @method buildCSSClass
*/
buildCSSClass() {
return `vjs-captions-button ${super.buildCSSClass()}`;
}
/**
* Update caption menu items
*
* @method update
*/
update() {
let threshold = 2;
super.update();
@ -34,6 +52,12 @@ class CaptionsButton extends TextTrackButton {
}
}
/**
* Create caption menu items
*
* @return {Array} Array of menu items
* @method createItems
*/
createItems() {
let items = [];

View File

@ -1,3 +1,6 @@
/**
* @file chapters-button.js
*/
import TextTrackButton from './text-track-button.js';
import Component from '../../component.js';
import TextTrackMenuItem from './text-track-menu-item.js';
@ -8,12 +11,16 @@ import * as Fn from '../../utils/fn.js';
import toTitleCase from '../../utils/to-title-case.js';
import window from 'global/window';
// Chapters act much differently than other text tracks
// Cues are navigation vs. other tracks of alternative languages
/**
* 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
*
* @constructor
* @param {Object} player Player object
* @param {Object=} options Object of option names and values
* @param {Function=} ready Ready callback function
* @extends TextTrackButton
* @class ChaptersButton
*/
class ChaptersButton extends TextTrackButton {
@ -22,11 +29,22 @@ class ChaptersButton extends TextTrackButton {
this.el_.setAttribute('aria-label','Chapters Menu');
}
/**
* Allow sub components to stack CSS class names
*
* @return {String} The constructed class name
* @method buildCSSClass
*/
buildCSSClass() {
return `vjs-chapters-button ${super.buildCSSClass()}`;
}
// Create a menu item for each text track
/**
* Create a menu item for each text track
*
* @return {Array} Array of menu items
* @method createItems
*/
createItems() {
let items = [];
@ -48,6 +66,12 @@ class ChaptersButton extends TextTrackButton {
return items;
}
/**
* Create menu from chapter buttons
*
* @return {Menu} Menu of chapter buttons
* @method createMenu
*/
createMenu() {
let tracks = this.player_.textTracks() || [];
let chaptersTrack;

View File

@ -1,9 +1,17 @@
/**
* @file chapters-track-menu-item.js
*/
import MenuItem from '../../menu/menu-item.js';
import Component from '../../component.js';
import * as Fn from '../../utils/fn.js';
/**
* @constructor
* The chapter track menu item
*
* @param {Player|Object} player
* @param {Object=} options
* @extends MenuItem
* @class ChaptersTrackMenuItem
*/
class ChaptersTrackMenuItem extends MenuItem {
@ -22,12 +30,22 @@ class ChaptersTrackMenuItem extends MenuItem {
track.addEventListener('cuechange', Fn.bind(this, this.update));
}
/**
* Handle click on menu item
*
* @method handleClick
*/
handleClick() {
super.handleClick();
this.player_.currentTime(this.cue.startTime);
this.update(this.cue.startTime);
}
/**
* Update chapter menu item
*
* @method update
*/
update() {
let cue = this.cue;
let currentTime = this.player_.currentTime();

View File

@ -1,10 +1,16 @@
/**
* @file off-text-track-menu-item.js
*/
import TextTrackMenuItem from './text-track-menu-item.js';
import Component from '../../component.js';
/**
* A special menu item for turning of a specific type of text track
*
* @constructor
* @param {Player|Object} player
* @param {Object=} options
* @extends TextTrackMenuItem
* @class OffTextTrackMenuItem
*/
class OffTextTrackMenuItem extends TextTrackMenuItem {
@ -23,6 +29,12 @@ class OffTextTrackMenuItem extends TextTrackMenuItem {
this.selected(true);
}
/**
* Handle text track change
*
* @param {Object} event Event object
* @method handleTracksChange
*/
handleTracksChange(event){
let tracks = this.player().textTracks();
let selected = true;

View File

@ -1,10 +1,17 @@
/**
* @file subtitles-button.js
*/
import TextTrackButton from './text-track-button.js';
import Component from '../../component.js';
/**
* The button component for toggling and selecting subtitles
*
* @constructor
* @param {Object} player Player object
* @param {Object=} options Object of option names and values
* @param {Function=} ready Ready callback function
* @extends TextTrackButton
* @class SubtitlesButton
*/
class SubtitlesButton extends TextTrackButton {
@ -13,6 +20,12 @@ class SubtitlesButton extends TextTrackButton {
this.el_.setAttribute('aria-label','Subtitles Menu');
}
/**
* Allow sub components to stack CSS class names
*
* @return {String} The constructed class name
* @method buildCSSClass
*/
buildCSSClass() {
return `vjs-subtitles-button ${super.buildCSSClass()}`;
}

View File

@ -1,3 +1,6 @@
/**
* @file text-track-button.js
*/
import MenuButton from '../../menu/menu-button.js';
import Component from '../../component.js';
import * as Fn from '../../utils/fn.js';
@ -7,7 +10,10 @@ import OffTextTrackMenuItem from './off-text-track-menu-item.js';
/**
* The base class for buttons that toggle specific text track types (e.g. subtitles)
*
* @constructor
* @param {Player|Object} player
* @param {Object=} options
* @extends MenuButton
* @class TextTrackButton
*/
class TextTrackButton extends MenuButton {

View File

@ -1,3 +1,6 @@
/**
* @file text-track-menu-item.js
*/
import MenuItem from '../../menu/menu-item.js';
import Component from '../../component.js';
import * as Fn from '../../utils/fn.js';
@ -7,7 +10,10 @@ import document from 'global/document';
/**
* The specific menu item type for selecting a language within a text track kind
*
* @constructor
* @param {Player|Object} player
* @param {Object=} options
* @extends MenuItem
* @class TextTrackMenuItem
*/
class TextTrackMenuItem extends MenuItem {
@ -58,6 +64,11 @@ class TextTrackMenuItem extends MenuItem {
}
}
/**
* Handle click on text track
*
* @method handleClick
*/
handleClick(event) {
let kind = this.track['kind'];
let tracks = this.player_.textTracks();
@ -81,6 +92,11 @@ class TextTrackMenuItem extends MenuItem {
}
}
/**
* Handle text track change
*
* @method handleTracksChange
*/
handleTracksChange(event){
this.selected(this.track['mode'] === 'showing');
}

View File

@ -1,12 +1,17 @@
/**
* @file current-time-display.js
*/
import Component from '../../component.js';
import * as Dom from '../../utils/dom.js';
import formatTime from '../../utils/format-time.js';
/**
* Displays the current time
*
* @param {Player|Object} player
* @param {Object=} options
* @constructor
* @extends Component
* @class CurrentTimeDisplay
*/
class CurrentTimeDisplay extends Component {
@ -16,6 +21,12 @@ class CurrentTimeDisplay extends Component {
this.on(player, 'timeupdate', this.updateContent);
}
/**
* Create the component's DOM element
*
* @return {Element}
* @method createEl
*/
createEl() {
let el = super.createEl('div', {
className: 'vjs-current-time vjs-time-control vjs-control'
@ -31,6 +42,11 @@ class CurrentTimeDisplay extends Component {
return el;
}
/**
* Update current time display
*
* @method updateContent
*/
updateContent() {
// Allows for smooth scrubbing, when player can't keep up.
let time = (this.player_.scrubbing) ? this.player_.getCache().currentTime : this.player_.currentTime();

View File

@ -1,12 +1,17 @@
/**
* @file duration-display.js
*/
import Component from '../../component.js';
import * as Dom from '../../utils/dom.js';
import formatTime from '../../utils/format-time.js';
/**
* Displays the duration
*
* @param {Player|Object} player
* @param {Object=} options
* @constructor
* @extends Component
* @class DurationDisplay
*/
class DurationDisplay extends Component {
@ -22,6 +27,12 @@ class DurationDisplay extends Component {
this.on(player, 'loadedmetadata', this.updateContent);
}
/**
* Create the component's DOM element
*
* @return {Element}
* @method createEl
*/
createEl() {
let el = super.createEl('div', {
className: 'vjs-duration vjs-time-control vjs-control'
@ -37,6 +48,11 @@ class DurationDisplay extends Component {
return el;
}
/**
* Update duration time display
*
* @method updateContent
*/
updateContent() {
let duration = this.player_.duration();
if (duration) {

View File

@ -1,12 +1,17 @@
/**
* @file remaining-time-display.js
*/
import Component from '../../component.js';
import * as Dom from '../../utils/dom.js';
import formatTime from '../../utils/format-time.js';
/**
* Displays the time left in the video
*
* @param {Player|Object} player
* @param {Object=} options
* @constructor
* @extends Component
* @class RemainingTimeDisplay
*/
class RemainingTimeDisplay extends Component {
@ -16,6 +21,12 @@ class RemainingTimeDisplay extends Component {
this.on(player, 'timeupdate', this.updateContent);
}
/**
* Create the component's DOM element
*
* @return {Element}
* @method createEl
*/
createEl() {
let el = super.createEl('div', {
className: 'vjs-remaining-time vjs-time-control vjs-control'
@ -31,6 +42,11 @@ class RemainingTimeDisplay extends Component {
return el;
}
/**
* Update remaining time display
*
* @method updateContent
*/
updateContent() {
if (this.player_.duration()) {
const localizedText = this.localize('Remaining Time');

View File

@ -1,16 +1,25 @@
/**
* @file time-divider.js
*/
import Component from '../../component.js';
/**
* The separator between the current time and duration
*
* The separator between the current time and duration.
* Can be hidden if it's not needed in the design.
*
* @param {Player|Object} player
* @param {Object=} options
* @constructor
* @extends Component
* @class TimeDivider
*/
class TimeDivider extends Component {
/**
* Create the component's DOM element
*
* @return {Element}
* @method createEl
*/
createEl() {
return super.createEl('div', {
className: 'vjs-time-control vjs-time-divider',

View File

@ -1,3 +1,6 @@
/**
* @file volume-bar.js
*/
import Slider from '../../slider/slider.js';
import Component from '../../component.js';
import * as Fn from '../../utils/fn.js';
@ -11,7 +14,8 @@ import VolumeLevel from './volume-level.js';
*
* @param {Player|Object} player
* @param {Object=} options
* @constructor
* @extends Slider
* @class VolumeBar
*/
class VolumeBar extends Slider {
@ -21,6 +25,12 @@ class VolumeBar extends Slider {
player.ready(Fn.bind(this, this.updateARIAAttributes));
}
/**
* Create the component's DOM element
*
* @return {Element}
* @method createEl
*/
createEl() {
return super.createEl('div', {
className: 'vjs-volume-bar',
@ -28,6 +38,11 @@ class VolumeBar extends Slider {
});
}
/**
* Handle mouse move on volume bar
*
* @method handleMouseMove
*/
handleMouseMove(event) {
if (this.player_.muted()) {
this.player_.muted(false);
@ -36,6 +51,12 @@ class VolumeBar extends Slider {
this.player_.volume(this.calculateDistance(event));
}
/**
* Get percent of volume level
*
* @retun {Number} Volume level percent
* @method getPercent
*/
getPercent() {
if (this.player_.muted()) {
return 0;
@ -44,14 +65,29 @@ class VolumeBar extends Slider {
}
}
/**
* Increase volume level for keyboard users
*
* @method stepForward
*/
stepForward() {
this.player_.volume(this.player_.volume() + 0.1);
}
/**
* Decrease volume level for keyboard users
*
* @method stepBack
*/
stepBack() {
this.player_.volume(this.player_.volume() - 0.1);
}
/**
* Update ARIA accessibility attributes
*
* @method updateARIAAttributes
*/
updateARIAAttributes() {
// Current value of volume bar as a percentage
this.el_.setAttribute('aria-valuenow', roundFloat(this.player_.volume()*100, 2));

View File

@ -1,3 +1,6 @@
/**
* @file volume-control.js
*/
import Component from '../../component.js';
// Required children
@ -8,7 +11,8 @@ import VolumeBar from './volume-bar.js';
*
* @param {Player|Object} player
* @param {Object=} options
* @constructor
* @extends Component
* @class VolumeControl
*/
class VolumeControl extends Component {
@ -28,6 +32,12 @@ class VolumeControl extends Component {
});
}
/**
* Create the component's DOM element
*
* @return {Element}
* @method createEl
*/
createEl() {
return super.createEl('div', {
className: 'vjs-volume-control vjs-control'

View File

@ -1,3 +1,6 @@
/**
* @file volume-level.js
*/
import Component from '../../component.js';
/**
@ -5,10 +8,17 @@ import Component from '../../component.js';
*
* @param {Player|Object} player
* @param {Object=} options
* @constructor
* @extends Component
* @class VolumeLevel
*/
class VolumeLevel extends Component {
/**
* Create the component's DOM element
*
* @return {Element}
* @method createEl
*/
createEl() {
return super.createEl('div', {
className: 'vjs-volume-level',

View File

@ -1,3 +1,6 @@
/**
* @file volume-menu-button.js
*/
import Button from '../button.js';
import Component from '../component.js';
import Menu from '../menu/menu.js';
@ -6,8 +9,12 @@ import MuteToggle from './mute-toggle.js';
import VolumeBar from './volume-control/volume-bar.js';
/**
* Menu button with a popup for showing the volume slider.
* @constructor
* Button for volume menu
*
* @param {Player|Object} player
* @param {Object=} options
* @extends MenuButton
* @class VolumeMenuButton
*/
class VolumeMenuButton extends MenuButton {
@ -31,10 +38,22 @@ class VolumeMenuButton extends MenuButton {
this.addClass('vjs-menu-button');
}
/**
* Allow sub components to stack CSS class names
*
* @return {String} The constructed class name
* @method buildCSSClass
*/
buildCSSClass() {
return `vjs-volume-menu-button ${super.buildCSSClass()}`;
}
/**
* Allow sub components to stack CSS class names
*
* @return {Menu} The volume menu button
* @method createMenu
*/
createMenu() {
let menu = new Menu(this.player_, {
contentElType: 'div'
@ -56,6 +75,11 @@ class VolumeMenuButton extends MenuButton {
return menu;
}
/**
* Handle click on volume menu and calls super
*
* @method handleClick
*/
handleClick() {
MuteToggle.prototype.handleClick.call(this);
super.handleClick();

View File

@ -1,11 +1,16 @@
/**
* @file error-display.js
*/
import Component from './component';
import * as Dom from './utils/dom.js';
import * as Dom from './utils/dom.js';
/**
* Display that an error has occurred making the video unplayable
* @param {Player|Object} player
* @param {Object=} options
* @constructor
*
* @param {Object} player Main Player
* @param {Object=} options Object of option names and values
* @extends Component
* @class ErrorDisplay
*/
class ErrorDisplay extends Component {
@ -16,6 +21,12 @@ class ErrorDisplay extends Component {
this.on(player, 'error', this.update);
}
/**
* Create the component's DOM element
*
* @return {Element}
* @method createEl
*/
createEl() {
var el = super.createEl('div', {
className: 'vjs-error-display'
@ -27,6 +38,11 @@ class ErrorDisplay extends Component {
return el;
}
/**
* Update the error message in localized language
*
* @method update
*/
update() {
if (this.player().error()) {
this.contentEl_.innerHTML = this.localize(this.player().error().message);

View File

@ -1,3 +1,6 @@
/**
* @file event-emitter.js
*/
import * as Events from './utils/events.js';
var EventEmitter = function() {};

View File

@ -1,4 +1,6 @@
/**
/*
* @file extends.js
*
* 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.
@ -23,18 +25,17 @@ const _inherits = function (subClass, superClass) {
}
};
/**
/*
* Function for subclassing using the same inheritance that
* videojs uses internally
*
* ```
* ```js
* var Button = videojs.getComponent('Button');
*
* ```
* ```js
* var MyButton = videojs.extends(Button, {
* constructor: function(player, options) {
* Button.call(this, player, options);
* },
*
* onClick: function() {
* // doSomething
* }

View File

@ -1,6 +1,9 @@
/**
* @file fullscreen-api.js
*/
import document from 'global/document';
/**
/*
* Store the browser-specific methods for the fullscreen API
* @type {Object|undefined}
* @private

View File

@ -1,12 +1,16 @@
/**
* @file global-options.js
*/
import document from 'global/document';
import window from 'global/window';
let navigator = window.navigator;
/**
/*
* Global Player instance options, surfaced from Player.prototype.options_
* options = Player.prototype.options_
* All options should use string keys so they avoid
* renaming by closure compiler
*
* @type {Object}
*/
export default {

View File

@ -1,15 +1,23 @@
/**
* @file loading-spinner.js
*/
import Component from './component';
/* Loading Spinner
================================================================================ */
/**
* Loading spinner for waiting events
* @param {Player|Object} player
* @param {Object=} options
* @class
* @constructor
*
* @extends Component
* @class LoadingSpinner
*/
class LoadingSpinner extends Component {
/**
* Create the component's DOM element
*
* @method createEl
*/
createEl() {
return super.createEl('div', {
className: 'vjs-loading-spinner'

View File

@ -1,7 +1,11 @@
/**
* @file media-error.js
*/
import assign from 'object.assign';
/**
/*
* Custom MediaError to mimic the HTML5 MediaError
*
* @param {Number} code The media error code
*/
let MediaError = function(code){
@ -19,29 +23,32 @@ let MediaError = function(code){
}
};
/**
/*
* The error code that refers two one of the defined
* MediaError types
*
* @type {Number}
*/
MediaError.prototype.code = 0;
/**
/*
* An optional message to be shown 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 the HLS plugin might provide the specific
* HTTP status code that was returned when the error
* occurred, then allowing a custom error overlay
* to display more information.
* @type {[type]}
*
* @type {Array}
*/
MediaError.prototype.status = null;

View File

@ -1,3 +1,6 @@
/**
* @file menu-button.js
*/
import Button from '../button.js';
import Component from '../component.js';
import Menu from './menu.js';
@ -7,9 +10,11 @@ import toTitleCase from '../utils/to-title-case.js';
/**
* A button class with a popup menu
*
* @param {Player|Object} player
* @param {Object=} options
* @constructor
* @extends Button
* @class MenuButton
*/
class MenuButton extends Button {
@ -23,6 +28,11 @@ class MenuButton extends Button {
this.el_.setAttribute('role', 'button');
}
/**
* Update menu
*
* @method update
*/
update() {
let menu = this.createMenu();
@ -35,6 +45,7 @@ class MenuButton extends Button {
/**
* Track the state of the menu button
*
* @type {Boolean}
* @private
*/
@ -47,6 +58,12 @@ class MenuButton extends Button {
}
}
/**
* Create menu
*
* @return {Menu} The constructed menu
* @method createMenu
*/
createMenu() {
var menu = new Menu(this.player_);
@ -73,33 +90,64 @@ class MenuButton extends Button {
/**
* Create the list of menu items. Specific to each subclass.
*
* @method createItems
*/
createItems(){}
/**
* Create the component's DOM element
*
* @return {Element}
* @method createEl
*/
createEl() {
return super.createEl('div', {
className: this.buildCSSClass()
});
}
/** @inheritDoc */
/**
* Allow sub components to stack CSS class names
*
* @return {String} The constructed class name
* @method buildCSSClass
*/
buildCSSClass() {
return `vjs-menu-button ${super.buildCSSClass()}`;
}
// Focus - Add keyboard functionality to element
// This function is not needed anymore. Instead, the keyboard functionality is handled by
// treating the button as triggering a submenu. When the button is pressed, the submenu
// appears. Pressing the button again makes the submenu disappear.
/**
* Focus - Add keyboard functionality to element
* This function is not needed anymore. Instead, the
* keyboard functionality is handled by
* treating the button as triggering a submenu.
* When the button is pressed, the submenu
* appears. Pressing the button again makes
* the submenu disappear.
*
* @method handleFocus
*/
handleFocus() {}
// Can't turn off list display that we turned on with focus, because list would go away.
/**
* Can't turn off list display that we turned
* on with focus, because list would go away.
*
* @method handleBlur
*/
handleBlur() {}
/**
* When you click the button it adds focus, which
* will show the menu indefinitely.
* So we'll remove focus when the mouse leaves the button.
* Focus is needed for tab navigation.
* Allow sub components to stack CSS class names
*
* @method handleClick
*/
handleClick() {
// When you click the button it adds focus, which will show the menu indefinitely.
// So we'll remove focus when the mouse leaves the button.
// Focus is needed for tab navigation.
this.one('mouseout', Fn.bind(this, function(){
this.menu.unlockShowing();
this.el_.blur();
@ -111,6 +159,12 @@ class MenuButton extends Button {
}
}
/**
* Handle key press on menu
*
* @param {Object} Key press event
* @method handleKeyPress
*/
handleKeyPress(event) {
// Check for space bar (32) or enter (13) keys
@ -130,6 +184,11 @@ class MenuButton extends Button {
}
}
/**
* Makes changes based on button pressed
*
* @method pressButton
*/
pressButton() {
this.buttonPressed_ = true;
this.menu.lockShowing();
@ -139,6 +198,11 @@ class MenuButton extends Button {
}
}
/**
* Makes changes based on button unpressed
*
* @method unpressButton
*/
unpressButton() {
this.buttonPressed_ = false;
this.menu.unlockShowing();

View File

@ -1,3 +1,6 @@
/**
* @file menu-item.js
*/
import Button from '../button.js';
import Component from '../component.js';
import assign from 'object.assign';
@ -7,8 +10,8 @@ import assign from 'object.assign';
*
* @param {Player|Object} player
* @param {Object=} options
* @class
* @constructor
* @extends Button
* @class MenuItem
*/
class MenuItem extends Button {
@ -17,7 +20,14 @@ class MenuItem extends Button {
this.selected(options['selected']);
}
/** @inheritDoc */
/**
* Create the component's DOM element
*
* @param {String=} type Desc
* @param {Object=} props Desc
* @return {Element}
* @method createEl
*/
createEl(type, props) {
return super.createEl('li', assign({
className: 'vjs-menu-item',
@ -27,6 +37,8 @@ class MenuItem extends Button {
/**
* Handle a click on the menu item, and set it to selected
*
* @method handleClick
*/
handleClick() {
this.selected(true);
@ -34,7 +46,9 @@ class MenuItem extends Button {
/**
* Set this menu item as selected or not
*
* @param {Boolean} selected
* @method selected
*/
selected(selected) {
if (selected) {

View File

@ -1,24 +1,25 @@
/**
* @file menu.js
*/
import Component from '../component.js';
import * as Dom from '../utils/dom.js';
import * as Fn from '../utils/fn.js';
import * as Events from '../utils/events.js';
/* Menu
================================================================================ */
/**
* The Menu component is used to build pop up menus, including subtitle and
* captions selection menus.
*
* @param {Player|Object} player
* @param {Object=} options
* @class
* @constructor
* @extends Component
* @class Menu
*/
class Menu extends Component {
/**
* Add a menu item to the menu
*
* @param {Object|String} component Component or component type to add
* @method addItem
*/
addItem(component) {
this.addChild(component);
@ -27,6 +28,12 @@ class Menu extends Component {
}));
}
/**
* Create the component's DOM element
*
* @return {Element}
* @method createEl
*/
createEl() {
let contentElType = this.options_.contentElType || 'ul';
this.contentEl_ = Dom.createEl(contentElType, {

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,6 @@
/**
* @file plugins.js
*/
import Player from './player.js';
/**
@ -5,6 +8,7 @@ import Player from './player.js';
*
* @param {String} name The name of the plugin
* @param {Function} init The function that is run when the player inits
* @method plugin
*/
var plugin = function(name, init){
Player.prototype[name] = init;

View File

@ -1,17 +1,19 @@
/**
* @file poster-image.js
*/
import Button from './button.js';
import Component from './component.js';
import * as Fn from './utils/fn.js';
import * as Dom from './utils/dom.js';
import * as browser from './utils/browser.js';
/* Poster Image
================================================================================ */
/**
* The component that handles showing the poster image.
*
* @param {Player|Object} player
* @param {Object=} options
* @constructor
* @extends Button
* @class PosterImage
*/
class PosterImage extends Button {
@ -24,6 +26,8 @@ class PosterImage extends Button {
/**
* Clean up the poster image
*
* @method dispose
*/
dispose() {
this.player().off('posterchange', this.update);
@ -31,8 +35,10 @@ class PosterImage extends Button {
}
/**
* Create the poster image element
* Create the poster's image element
*
* @return {Element}
* @method createEl
*/
createEl() {
let el = Dom.createEl('div', {
@ -56,6 +62,8 @@ class PosterImage extends Button {
/**
* Event handler for updates to the player's poster source
*
* @method update
*/
update() {
let url = this.player().poster();
@ -73,6 +81,9 @@ class PosterImage extends Button {
/**
* Set the poster source depending on the display method
*
* @param {String} url The URL to the poster source
* @method setSrc
*/
setSrc(url) {
if (this.fallbackImg_) {
@ -91,6 +102,8 @@ class PosterImage extends Button {
/**
* Event handler for clicks on the poster image
*
* @method handleClick
*/
handleClick() {
// We don't want a click to trigger playback when controls are disabled

View File

@ -1,3 +1,9 @@
/**
* @file setup.js
*
* Functions for automatically setting up a player
* based on the data-setup attribute of the video tag
*/
import * as Events from './utils/events.js';
import document from 'global/document';
import window from 'global/window';
@ -5,10 +11,6 @@ import window from 'global/window';
let _windowLoaded = false;
let videojs;
/**
* @fileoverview Functions for automatically setting up a player
* based on the data-setup attribute of the video tag
*/
// Automatically set up any tags that have a data-setup attribute
var autoSetup = function(){

View File

@ -1,17 +1,19 @@
/**
* @file slider.js
*/
import Component from '../component.js';
import * as Dom from '../utils/dom.js';
import roundFloat from '../utils/round-float.js';
import document from 'global/document';
import assign from 'object.assign';
/* Slider
================================================================================ */
/**
* The base functionality for sliders like the volume bar and seek bar
*
* @param {Player|Object} player
* @param {Object=} options
* @constructor
* @extends Component
* @class Slider
*/
class Slider extends Component {
@ -35,6 +37,14 @@ class Slider extends Component {
this.on(player, this.playerEvent, this.update);
}
/**
* Create the component's DOM element
*
* @param {String} type Type of element to create
* @param {Object=} props List of properties in Object form
* @return {Element}
* @method createEl
*/
createEl(type, props={}) {
// Add the slider element class to all sub classes
props.className = props.className + ' vjs-slider';
@ -49,6 +59,12 @@ class Slider extends Component {
return super.createEl(type, props);
}
/**
* Handle mouse down on slider
*
* @param {Object} event Mouse down event object
* @method handleMouseDown
*/
handleMouseDown(event) {
event.preventDefault();
Dom.blockTextSelection();
@ -62,9 +78,18 @@ class Slider extends Component {
this.handleMouseMove(event);
}
// To be overridden by a subclass
/**
* To be overridden by a subclass
*
* @method handleMouseMove
*/
handleMouseMove() {}
/**
* Handle mouse up on Slider
*
* @method handleMouseUp
*/
handleMouseUp() {
Dom.unblockTextSelection();
this.removeClass('vjs-sliding');
@ -77,6 +102,11 @@ class Slider extends Component {
this.update();
}
/**
* Update slider
*
* @method update
*/
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
@ -110,6 +140,12 @@ class Slider extends Component {
}
}
/**
* Calculate distance for slider
*
* @param {Object} event Event object
* @method calculateDistance
*/
calculateDistance(event){
let el = this.el_;
let box = Dom.findElPosition(el);
@ -160,10 +196,21 @@ class Slider extends Component {
}
}
/**
* Handle on focus for slider
*
* @method handleFocus
*/
handleFocus() {
this.on(document, 'keydown', this.handleKeyPress);
}
/**
* Handle key press for slider
*
* @param {Object} event Event object
* @method handleKeyPress
*/
handleKeyPress(event) {
if (event.which === 37 || event.which === 40) { // Left and Down Arrows
event.preventDefault();
@ -174,6 +221,11 @@ class Slider extends Component {
}
}
/**
* Handle on blur for slider
*
* @method handleBlur
*/
handleBlur() {
this.off(document, 'keydown', this.handleKeyPress);
}
@ -181,13 +233,22 @@ class Slider extends Component {
/**
* Listener for click events on slider, used to prevent clicks
* from bubbling up to parent elements like button menus.
* @param {Object} event Event object
*
* @param {Object} event Event object
* @method handleClick
*/
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} True if slider is vertical, false is horizontal
* @method vertical
*/
vertical(bool) {
if (bool === undefined) {
return this.vertical_ || false;

View File

@ -1,3 +1,6 @@
/**
* @file flash-rtmp.js
*/
function FlashRtmpDecorator(Flash) {
Flash.streamingFormats = {
'rtmp/mp4': 'MP4',

View File

@ -1,5 +1,6 @@
/**
* @fileoverview VideoJS-SWF - Custom Flash Player with HTML5-ish API
* @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
*/
@ -17,10 +18,10 @@ let navigator = window.navigator;
/**
* Flash Media Controller - Wrapper for fallback SWF API
*
* @param {Player} player
* @param {Object=} options
* @param {Function=} ready
* @constructor
* @param {Object=} options Object of option names and values
* @param {Function=} ready Ready callback function
* @extends Tech
* @class Flash
*/
class Flash extends Tech {
@ -55,6 +56,12 @@ class Flash extends Tech {
window.videojs.Flash.onError = Flash.onError;
}
/**
* Create the component's DOM element
*
* @return {Element}
* @method createEl
*/
createEl() {
let options = this.options_;
@ -96,14 +103,31 @@ class Flash extends Tech {
return this.el_;
}
/**
* Play for flash tech
*
* @method play
*/
play() {
this.el_.vjs_play();
}
/**
* Pause for flash tech
*
* @method pause
*/
pause() {
this.el_.vjs_pause();
}
/**
* Get/set video
*
* @param {Object=} src Source object
* @return {Object}
* @method src
*/
src(src) {
if (src === undefined) {
return this.currentSrc();
@ -113,6 +137,13 @@ class Flash extends Tech {
return this.setSrc(src);
}
/**
* Set video
*
* @param {Object=} src Source object
* @deprecated
* @method setSrc
*/
setSrc(src) {
// Make sure source URL is absolute.
src = Url.getAbsoluteURL(src);
@ -126,12 +157,25 @@ class Flash extends Tech {
}
}
/**
* Set current time
*
* @param {Number} time Current time of video
* @method setCurrentTime
*/
setCurrentTime(time) {
this.lastSeekTarget_ = time;
this.el_.vjs_setProperty('currentTime', time);
super.setCurrentTime();
}
/**
* Get current time
*
* @param {Number=} time Current time of video
* @return {Number} Current time
* @method currentTime
*/
currentTime(time) {
// when seeking make the reported time keep up with the requested time
// by reading the time we're seeking to
@ -141,6 +185,11 @@ class Flash extends Tech {
return this.el_.vjs_getProperty('currentTime');
}
/**
* Get current source
*
* @method currentSrc
*/
currentSrc() {
if (this.currentSource_) {
return this.currentSource_.src;
@ -149,17 +198,37 @@ class Flash extends Tech {
}
}
/**
* Load media into player
*
* @method load
*/
load() {
this.el_.vjs_load();
}
/**
* Get poster
*
* @method poster
*/
poster() {
this.el_.vjs_getProperty('poster');
}
// poster images are not handled by the Flash tech so make this a no-op
/**
* Poster images are not handled by the Flash tech so make this a no-op
*
* @method setPoster
*/
setPoster() {}
/**
* Determine if can seek in media
*
* @return {TimeRangeObject}
* @method seekable
*/
seekable() {
const duration = this.duration();
if (duration === 0) {
@ -168,14 +237,36 @@ class Flash extends Tech {
return createTimeRange(0, duration);
}
/**
* Get buffered time range
*
* @return {TimeRangeObject}
* @method buffered
*/
buffered() {
return createTimeRange(0, this.el_.vjs_getProperty('buffered'));
}
/**
* Get fullscreen support -
* Flash does not allow fullscreen through javascript
* so always returns false
*
* @return {Boolean} false
* @method supportsFullScreen
*/
supportsFullScreen() {
return false; // Flash does not allow fullscreen through javascript
}
/**
* Request to enter fullscreen
* Flash does not allow fullscreen through javascript
* so always returns false
*
* @return {Boolean} false
* @method enterFullScreen
*/
enterFullScreen() {
return false;
}
@ -217,16 +308,18 @@ Flash.isSupported = function(){
// Add Source Handler pattern functions to this tech
Tech.withSourceHandlers(Flash);
/**
/*
* The default native source handler.
* This simply passes the source to the video element. Nothing fancy.
*
* @param {Object} source The source object
* @param {Flash} tech The instance of the Flash tech
*/
Flash.nativeSourceHandler = {};
/**
/*
* Check Flash can handle the source natively
*
* @param {Object} source The source object
* @return {String} 'probably', 'maybe', or '' (empty string)
*/
@ -255,10 +348,11 @@ Flash.nativeSourceHandler.canHandleSource = function(source){
return '';
};
/**
/*
* Pass the source to the flash object
* Adaptive source handlers will have more complicated workflows before passing
* video data to the video element
*
* @param {Object} source The source object
* @param {Flash} tech The instance of the Flash tech
*/
@ -266,7 +360,7 @@ Flash.nativeSourceHandler.handleSource = function(source, tech){
tech.setSrc(source.src);
};
/**
/*
* Clean up the source handler when disposing the player or switching sources..
* (no cleanup is needed when supporting the format natively)
*/

View File

@ -1,5 +1,6 @@
/**
* @fileoverview HTML5 Media Controller - Wrapper for HTML5 Media API
* @file html5.js
* HTML5 Media Controller - Wrapper for HTML5 Media API
*/
import Tech from './tech.js';
@ -16,10 +17,11 @@ import mergeOptions from '../utils/merge-options.js';
/**
* HTML5 Media Controller - Wrapper for HTML5 Media API
* @param {Player|Object} player
* @param {Object=} options
* @param {Function=} ready
* @constructor
*
* @param {Object=} options Object of option names and values
* @param {Function=} ready Ready callback function
* @extends Tech
* @class Html5
*/
class Html5 extends Tech {
@ -78,12 +80,22 @@ class Html5 extends Tech {
this.triggerReady();
}
/**
* Dispose of html5 media element
*
* @method dispose
*/
dispose() {
Html5.disposeMediaElement(this.el_);
super.dispose();
}
/**
* Create the component's DOM element
*
* @return {Element}
* @method createEl
*/
createEl() {
let el = this.options_.tag;
@ -147,6 +159,11 @@ class Html5 extends Tech {
}
/**
* Hide captions from text track
*
* @method hideCaptions
*/
hideCaptions() {
let tracks = this.el_.querySelectorAll('track');
let i = tracks.length;
@ -164,11 +181,42 @@ class Html5 extends Tech {
}
}
/**
* Play for html5 tech
*
* @method play
*/
play() { this.el_.play(); }
/**
* Pause for html5 tech
*
* @method pause
*/
pause() { this.el_.pause(); }
/**
* Paused for html5 tech
*
* @return {Boolean}
* @method paused
*/
paused() { return this.el_.paused; }
/**
* Get current time
*
* @return {Number}
* @method currentTime
*/
currentTime() { return this.el_.currentTime; }
/**
* Set current time
*
* @param {Number} seconds Current time of video
* @method setCurrentTime
*/
setCurrentTime(seconds) {
try {
this.el_.currentTime = seconds;
@ -178,19 +226,78 @@ class Html5 extends Tech {
}
}
/**
* Get duration
*
* @return {Number}
* @method duration
*/
duration() { return this.el_.duration || 0; }
/**
* Get a TimeRange object that represents the intersection
* of the time ranges for which the user agent has all
* relevant media
*
* @return {TimeRangeObject}
* @method buffered
*/
buffered() { return this.el_.buffered; }
/**
* Get volume level
*
* @return {Number}
* @method volume
*/
volume() { return this.el_.volume; }
/**
* Set volume level
*
* @param {Number} percentAsDecimal Volume percent as a decimal
* @method setVolume
*/
setVolume(percentAsDecimal) { this.el_.volume = percentAsDecimal; }
/**
* Get if muted
*
* @return {Boolean}
* @method muted
*/
muted() { return this.el_.muted; }
/**
* Set muted
*
* @param {Boolean} If player is to be muted or note
* @method setMuted
*/
setMuted(muted) { this.el_.muted = muted; }
/**
* Get player width
*
* @return {Number}
* @method width
*/
width() { return this.el_.offsetWidth; }
/**
* Get player height
*
* @return {Number}
* @method height
*/
height() { return this.el_.offsetHeight; }
/**
* Get if there is fullscreen support
*
* @return {Boolean}
* @method supportsFullScreen
*/
supportsFullScreen() {
if (typeof this.el_.webkitEnterFullScreen === 'function') {
let userAgent = window.navigator.userAgent;
@ -202,6 +309,11 @@ class Html5 extends Tech {
return false;
}
/**
* Request to enter fullscreen
*
* @method enterFullScreen
*/
enterFullScreen() {
var video = this.el_;
@ -231,10 +343,22 @@ class Html5 extends Tech {
}
}
/**
* Request to exit fullscreen
*
* @method exitFullScreen
*/
exitFullScreen() {
this.el_.webkitExitFullScreen();
}
/**
* Get/set video
*
* @param {Object=} src Source object
* @return {Object}
* @method src
*/
src(src) {
if (src === undefined) {
return this.el_.src;
@ -244,42 +368,220 @@ class Html5 extends Tech {
}
}
/**
* Set video
*
* @param {Object} src Source object
* @deprecated
* @method setSrc
*/
setSrc(src) { this.el_.src = src; }
/**
* Load media into player
*
* @method load
*/
load(){ this.el_.load(); }
/**
* Get current source
*
* @return {Object}
* @method currentSrc
*/
currentSrc() { return this.el_.currentSrc; }
/**
* Get poster
*
* @return {String}
* @method poster
*/
poster() { return this.el_.poster; }
/**
* Set poster
*
* @param {String} val URL to poster image
* @method
*/
setPoster(val) { this.el_.poster = val; }
/**
* Get preload attribute
*
* @return {String}
* @method preload
*/
preload() { return this.el_.preload; }
/**
* Set preload attribute
*
* @param {String} val Value for preload attribute
* @method setPreload
*/
setPreload(val) { this.el_.preload = val; }
/**
* Get autoplay attribute
*
* @return {String}
* @method autoplay
*/
autoplay() { return this.el_.autoplay; }
/**
* Set autoplay attribute
*
* @param {String} val Value for preload attribute
* @method setAutoplay
*/
setAutoplay(val) { this.el_.autoplay = val; }
/**
* Get controls attribute
*
* @return {String}
* @method controls
*/
controls() { return this.el_.controls; }
/**
* Set controls attribute
*
* @param {String} val Value for controls attribute
* @method setControls
*/
setControls(val) { this.el_.controls = !!val; }
/**
* Get loop attribute
*
* @return {String}
* @method loop
*/
loop() { return this.el_.loop; }
/**
* Set loop attribute
*
* @param {String} val Value for loop attribute
* @method setLoop
*/
setLoop(val) { this.el_.loop = val; }
/**
* Get error value
*
* @return {String}
* @method error
*/
error() { return this.el_.error; }
/**
* Get whether or not the player is in the "seeking" state
*
* @return {Boolean}
* @method seeking
*/
seeking() { return this.el_.seeking; }
/**
* Get a TimeRanges object that represents the
* ranges of the media resource to which it is possible
* for the user agent to seek.
*
* @return {TimeRangeObject}
* @method seekable
*/
seekable() { return this.el_.seekable; }
/**
* Get if video ended
*
* @return {Boolean}
* @method ended
*/
ended() { return this.el_.ended; }
/**
* Get the value of the muted content attribute
* This attribute has no dynamic effect, it only
* controls the default state of the element
*
* @return {Boolean}
* @method defaultMuted
*/
defaultMuted() { return this.el_.defaultMuted; }
/**
* Get desired speed at which the media resource is to play
*
* @return {Number}
* @method playbackRate
*/
playbackRate() { return this.el_.playbackRate; }
/**
* Set desired speed at which the media resource is to play
*
* @param {Number} val Speed at which the media resource is to play
* @method setPlaybackRate
*/
setPlaybackRate(val) { this.el_.playbackRate = val; }
/**
* Get the current state of network activity for the element, from
* the list below
* NETWORK_EMPTY (numeric value 0)
* NETWORK_IDLE (numeric value 1)
* NETWORK_LOADING (numeric value 2)
* NETWORK_NO_SOURCE (numeric value 3)
*
* @return {Number}
* @method networkState
*/
networkState() { return this.el_.networkState; }
/**
* Get 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)
* HAVE_METADATA (numeric value 1)
* HAVE_CURRENT_DATA (numeric value 2)
* HAVE_FUTURE_DATA (numeric value 3)
* HAVE_ENOUGH_DATA (numeric value 4)
*
* @return {Number}
* @method readyState
*/
readyState() { return this.el_.readyState; }
/**
* Get width of video
*
* @return {Number}
* @method videoWidth
*/
videoWidth() { return this.el_.videoWidth; }
/**
* Get height of video
*
* @return {Number}
* @method videoHeight
*/
videoHeight() { return this.el_.videoHeight; }
/**
* Get text tracks
*
* @return {TextTrackList}
* @method textTracks
*/
textTracks() {
if (!this['featuresNativeTextTracks']) {
return super.textTracks();
@ -287,6 +589,17 @@ class Html5 extends Tech {
return this.el_.textTracks;
}
/**
* Creates and returns a text track object
*
* @param {String} kind Text track kind (subtitles, captions, descriptions
* chapters and metadata)
* @param {String=} label Label to identify the text track
* @param {String=} language Two letter language abbreviation
* @return {TextTrackObject}
* @method addTextTrack
*/
addTextTrack(kind, label, language) {
if (!this['featuresNativeTextTracks']) {
return super.addTextTrack(kind, label, language);
@ -295,6 +608,14 @@ class Html5 extends Tech {
return this.el_.addTextTrack(kind, label, language);
}
/**
* Creates and returns a remote text track object
*
* @param {Object} options The object should contain values for
* kind, language, label and src (location of the WebVTT file)
* @return {TextTrackObject}
* @method addRemoteTextTrack
*/
addRemoteTextTrack(options={}) {
if (!this['featuresNativeTextTracks']) {
return super.addRemoteTextTrack(options);
@ -346,6 +667,12 @@ class Html5 extends Tech {
return track;
}
/**
* Remove remote text track from TextTrackList object
*
* @param {TextTrackObject} track Texttrack object to remove
* @method removeRemoteTextTrack
*/
removeRemoteTextTrack(track) {
if (!this['featuresNativeTextTracks']) {
return super.removeRemoteTextTrack(track);
@ -370,12 +697,13 @@ class Html5 extends Tech {
/* HTML5 Support Testing ---------------------------------------------------- */
/**
* Element for testing browser HTML5 video capabilities
* @type {Element}
* @constant
* @private
*/
/*
* Element for testing browser HTML5 video capabilities
*
* @type {Element}
* @constant
* @private
*/
Html5.TEST_VID = document.createElement('video');
let track = document.createElement('track');
track.kind = 'captions';
@ -383,8 +711,9 @@ track.srclang = 'en';
track.label = 'English';
Html5.TEST_VID.appendChild(track);
/**
/*
* Check if HTML5 video is supported by this browser/device
*
* @return {Boolean}
*/
Html5.isSupported = function(){
@ -401,16 +730,18 @@ Html5.isSupported = function(){
// Add Source Handler pattern functions to this tech
Tech.withSourceHandlers(Html5);
/**
/*
* The default native source handler.
* This simply passes the source to the video element. Nothing fancy.
*
* @param {Object} source The source object
* @param {Html5} tech The instance of the HTML5 tech
*/
Html5.nativeSourceHandler = {};
/**
/*
* Check if the video element can handle the source natively
*
* @param {Object} source The source object
* @return {String} 'probably', 'maybe', or '' (empty string)
*/
@ -440,10 +771,11 @@ Html5.nativeSourceHandler.canHandleSource = function(source){
return '';
};
/**
/*
* Pass the source to the video element
* Adaptive source handlers will have more complicated workflows before passing
* video data to the video element
*
* @param {Object} source The source object
* @param {Html5} tech The instance of the Html5 tech
*/
@ -451,19 +783,20 @@ Html5.nativeSourceHandler.handleSource = function(source, tech){
tech.setSrc(source.src);
};
/**
* Clean up the source handler when disposing the player or switching sources..
* (no cleanup is needed when supporting the format natively)
*/
/*
* Clean up the source handler when disposing the player or switching sources..
* (no cleanup is needed when supporting the format natively)
*/
Html5.nativeSourceHandler.dispose = function(){};
// Register the native source handler
Html5.registerSourceHandler(Html5.nativeSourceHandler);
/**
/*
* 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}
*/
Html5.canControlVolume = function(){
@ -472,9 +805,10 @@ Html5.canControlVolume = function(){
return volume !== Html5.TEST_VID.volume;
};
/**
/*
* Check if playbackRate is supported in this browser/device.
* @return {[type]} [description]
*
* @return {Number} [description]
*/
Html5.canControlPlaybackRate = function(){
var playbackRate = Html5.TEST_VID.playbackRate;
@ -482,8 +816,9 @@ Html5.canControlPlaybackRate = function(){
return playbackRate !== Html5.TEST_VID.playbackRate;
};
/**
/*
* Check to see if native text tracks are supported by this browser/device
*
* @return {Boolean}
*/
Html5.supportsNativeTextTracks = function() {
@ -505,40 +840,44 @@ Html5.supportsNativeTextTracks = function() {
return supportsTextTracks;
};
/**
/*
* Set the tech's volume control support status
*
* @type {Boolean}
*/
Html5.prototype['featuresVolumeControl'] = Html5.canControlVolume();
/**
/*
* Set the tech's playbackRate support status
*
* @type {Boolean}
*/
Html5.prototype['featuresPlaybackRate'] = Html5.canControlPlaybackRate();
/**
/*
* Set the tech's status on moving the video element.
* In iOS, if you move a video element in the DOM, it breaks video playback.
*
* @type {Boolean}
*/
Html5.prototype['movingMediaElementInDOM'] = !browser.IS_IOS;
/**
/*
* Set the the tech's fullscreen resize support status.
* HTML video is able to automatically resize when going to fullscreen.
* (No longer appears to be used. Can probably be removed.)
*/
Html5.prototype['featuresFullscreenResize'] = true;
/**
/*
* Set the tech's progress event support status
* (this disables the manual progress events of the Tech)
*/
Html5.prototype['featuresProgressEvents'] = true;
/**
/*
* Sets the tech's status on native text track support
*
* @type {Boolean}
*/
Html5.prototype['featuresNativeTextTracks'] = Html5.supportsNativeTextTracks();

View File

@ -1,3 +1,6 @@
/**
* @file loader.js
*/
import Component from '../component';
import window from 'global/window';
import toTitleCase from '../utils/to-title-case.js';
@ -6,7 +9,11 @@ import toTitleCase from '../utils/to-title-case.js';
* The Media Loader is the component that decides which playback technology to load
* when the player is initialized.
*
* @constructor
* @param {Object} player Main Player
* @param {Object=} options Object of option names and values
* @param {Function=} ready Ready callback function
* @extends Component
* @class MediaLoader
*/
class MediaLoader extends Component {

View File

@ -1,5 +1,6 @@
/**
* @fileoverview Media Technology Controller - Base class for media playback
* @file tech.js
* Media Technology Controller - Base class for media playback
* technology controllers like Flash and HTML5
*/
@ -15,9 +16,11 @@ import document from 'global/document';
/**
* Base class for media (HTML5 Video, Flash) controllers
* @param {Player|Object} player Central player instance
*
* @param {Object=} options Options object
* @constructor
* @param {Function=} ready Ready callback function
* @extends Component
* @class Tech
*/
class Tech extends Component {
@ -61,19 +64,18 @@ class Tech extends Component {
* on a mobile device a click on the video toggles controls.
* (toggling controls 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
*
* @method initControlsListeners
*/
initControlsListeners() {
// if we're loading the playback object after it has started loading or playing the
@ -92,6 +94,11 @@ class Tech extends Component {
================================================================================ */
// Manually trigger progress events based on changes to the buffered amount
// Many flash players and older HTML5 browsers don't send progress or progress-like events
/**
* Turn on progress events
*
* @method manualProgressOn
*/
manualProgressOn() {
this.on('durationchange', this.onDurationChange);
@ -101,6 +108,11 @@ class Tech extends Component {
this.trackProgress();
}
/**
* Turn off progress events
*
* @method manualProgressOff
*/
manualProgressOff() {
this.manualProgress = false;
this.stopTrackingProgress();
@ -108,6 +120,11 @@ class Tech extends Component {
this.off('durationchange', this.onDurationChange);
}
/**
* Track progress
*
* @method trackProgress
*/
trackProgress() {
this.progressInterval = this.setInterval(Fn.bind(this, function(){
// Don't trigger unless buffered amount is greater than last time
@ -126,23 +143,50 @@ class Tech extends Component {
}), 500);
}
/**
* Update duration
*
* @method onDurationChange
*/
onDurationChange() {
this.duration_ = this.duration();
}
/**
* Create and get TimeRange object for buffering
*
* @return {TimeRangeObject}
* @method buffered
*/
buffered() {
return createTimeRange(0, 0);
}
/**
* Get buffered percent
*
* @return {Number}
* @method bufferedPercent
*/
bufferedPercent() {
return bufferedPercent(this.buffered(), this.duration_);
}
/**
* Stops tracking progress by clearing progress interval
*
* @method stopTrackingProgress
*/
stopTrackingProgress() {
this.clearInterval(this.progressInterval);
}
/*! Time Tracking -------------------------------------------------------------- */
/**
* Set event listeners for on play and pause and tracking current time
*
* @method manualTimeUpdatesOn
*/
manualTimeUpdatesOn() {
this.manualTimeUpdates = true;
@ -150,6 +194,11 @@ class Tech extends Component {
this.on('pause', this.stopTrackingCurrentTime);
}
/**
* Remove event listeners for on play and pause and tracking current time
*
* @method manualTimeUpdatesOff
*/
manualTimeUpdatesOff() {
this.manualTimeUpdates = false;
this.stopTrackingCurrentTime();
@ -157,6 +206,11 @@ class Tech extends Component {
this.off('pause', this.stopTrackingCurrentTime);
}
/**
* Tracks current time
*
* @method trackCurrentTime
*/
trackCurrentTime() {
if (this.currentTimeInterval) { this.stopTrackingCurrentTime(); }
this.currentTimeInterval = this.setInterval(function(){
@ -164,7 +218,11 @@ class Tech extends Component {
}, 250); // 42 = 24 fps // 250 is what Webkit uses // FF uses 15
}
// Turn off play progress tracking (when paused or dragging)
/**
* Turn off play progress tracking (when paused or dragging)
*
* @method stopTrackingCurrentTime
*/
stopTrackingCurrentTime() {
this.clearInterval(this.currentTimeInterval);
@ -173,6 +231,11 @@ class Tech extends Component {
this.trigger({ type: 'timeupdate', target: this, manuallyTriggered: true });
}
/**
* Turn off any manual progress or timeupdate tracking
*
* @method dispose
*/
dispose() {
// Turn off any manual progress or timeupdate tracking
if (this.manualProgress) { this.manualProgressOff(); }
@ -182,11 +245,21 @@ class Tech extends Component {
super.dispose();
}
/**
* Set current time
*
* @method setCurrentTime
*/
setCurrentTime() {
// improve the accuracy of manual timeupdates
if (this.manualTimeUpdates) { this.trigger({ type: 'timeupdate', target: this, manuallyTriggered: true }); }
}
/**
* Initialize texttrack listeners
*
* @method initTextTrackListeners
*/
initTextTrackListeners() {
let textTrackListChanges = Fn.bind(this, function() {
this.trigger('texttrackchange');
@ -205,6 +278,11 @@ class Tech extends Component {
}));
}
/**
* Emulate texttracks
*
* @method emulateTextTracks
*/
emulateTextTracks() {
if (!window['WebVTT'] && this.el().parentNode != null) {
let script = document.createElement('script');
@ -239,22 +317,44 @@ class Tech extends Component {
});
}
/**
/*
* Provide default methods for text tracks.
*
* Html5 tech overrides these.
*/
/**
* Get texttracks
*
* @returns {TextTrackList}
* @method textTracks
*/
textTracks() {
this.textTracks_ = this.textTracks_ || new TextTrackList();
return this.textTracks_;
}
/**
* Get remote texttracks
*
* @returns {TextTrackList}
* @method remoteTextTracks
*/
remoteTextTracks() {
this.remoteTextTracks_ = this.remoteTextTracks_ || new TextTrackList();
return this.remoteTextTracks_;
}
/**
* Creates and returns a remote text track object
*
* @param {String} kind Text track kind (subtitles, captions, descriptions
* chapters and metadata)
* @param {String=} label Label to identify the text track
* @param {String=} language Two letter language abbreviation
* @return {TextTrackObject}
* @method addTextTrack
*/
addTextTrack(kind, label, language) {
if (!kind) {
throw new Error('TextTrack kind is required but was not provided');
@ -263,6 +363,14 @@ class Tech extends Component {
return createTrackHelper(this, kind, label, language);
}
/**
* Creates and returns a remote text track object
*
* @param {Object} options The object should contain values for
* kind, language, label and src (location of the WebVTT file)
* @return {TextTrackObject}
* @method addRemoteTextTrack
*/
addRemoteTextTrack(options) {
let track = createTrackHelper(this, options.kind, options.label, options.language, options);
this.remoteTextTracks().addTrack_(track);
@ -271,6 +379,12 @@ class Tech extends Component {
};
}
/**
* Remove remote texttrack
*
* @param {TextTrackObject} track Texttrack to remove
* @method removeRemoteTextTrack
*/
removeRemoteTextTrack(track) {
this.textTracks().removeTrack_(track);
this.remoteTextTracks().removeTrack_(track);
@ -278,16 +392,18 @@ class Tech extends Component {
/**
* Provide a default setPoster method for techs
*
* Poster support for techs should be optional, so we don't want techs to
* break if they don't have a way to set a poster.
*
* @method setPoster
*/
setPoster() {}
}
/**
/*
* List of associated text tracks
*
* @type {Array}
* @private
*/
@ -325,8 +441,8 @@ Tech.prototype.featuresTimeupdateEvents = false;
Tech.prototype.featuresNativeTextTracks = false;
/**
* A functional mixin for techs that want to use the Source Handler pattern.
/*
* A functional mixin for techs that want to use the Source Handler pattern.
*
* ##### EXAMPLE:
*
@ -334,14 +450,14 @@ Tech.prototype.featuresNativeTextTracks = false;
*
*/
Tech.withSourceHandlers = function(_Tech){
/**
* Register a source handler
* 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)
* @param {Function} handler The source handler
* @param {Boolean} first Register it before any existing handlers
*/
/*
* Register a source handler
* 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)
* @param {Function} handler The source handler
* @param {Boolean} first Register it before any existing handlers
*/
_Tech.registerSourceHandler = function(handler, index){
let handlers = _Tech.sourceHandlers;
@ -357,13 +473,13 @@ Tech.withSourceHandlers = function(_Tech){
handlers.splice(index, 0, handler);
};
/**
* Return the first source handler that supports the source
* TODO: Answer question: should 'probably' be prioritized over 'maybe'
* @param {Object} source The source object
* @returns {Object} The first source handler that supports the source
* @returns {null} Null if no source handler is found
*/
/*
* Return the first source handler that supports the source
* TODO: Answer question: should 'probably' be prioritized over 'maybe'
* @param {Object} source The source object
* @returns {Object} The first source handler that supports the source
* @returns {null} Null if no source handler is found
*/
_Tech.selectSourceHandler = function(source){
let handlers = _Tech.sourceHandlers || [];
let can;
@ -379,11 +495,11 @@ Tech.withSourceHandlers = function(_Tech){
return null;
};
/**
* Check if the tech can support the given source
* @param {Object} srcObj The source object
* @return {String} 'probably', 'maybe', or '' (empty string)
*/
/*
* Check if the tech can support the given source
* @param {Object} srcObj The source object
* @return {String} 'probably', 'maybe', or '' (empty string)
*/
_Tech.canPlaySource = function(srcObj){
let sh = _Tech.selectSourceHandler(srcObj);
@ -394,13 +510,13 @@ Tech.withSourceHandlers = function(_Tech){
return '';
};
/**
* 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 {Object} source A source object with src and type keys
* @return {Tech} self
*/
/*
* 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 {Object} source A source object with src and type keys
* @return {Tech} self
*/
_Tech.prototype.setSource = function(source){
let sh = _Tech.selectSourceHandler(source);
@ -425,9 +541,9 @@ Tech.withSourceHandlers = function(_Tech){
return this;
};
/**
* Clean up any existing source handler
*/
/*
* Clean up any existing source handler
*/
_Tech.prototype.disposeSourceHandler = function(){
if (this.sourceHandler_ && this.sourceHandler_.dispose) {
this.sourceHandler_.dispose();

View File

@ -1,3 +1,6 @@
/**
* @file text-track-cue-list.js
*/
import * as browser from '../utils/browser.js';
import document from 'global/document';

View File

@ -1,3 +1,6 @@
/**
* @file text-track-display.js
*/
import Component from '../component';
import Menu from '../menu/menu.js';
import MenuItem from '../menu/menu-item.js';
@ -24,7 +27,11 @@ const fontMap = {
/**
* The component for displaying text track cues
*
* @constructor
* @param {Object} player Main Player
* @param {Object=} options Object of option names and values
* @param {Function=} ready Ready callback function
* @extends Component
* @class TextTrackDisplay
*/
class TextTrackDisplay extends Component {
@ -54,6 +61,11 @@ class TextTrackDisplay extends Component {
}));
}
/**
* Toggle display texttracks
*
* @method toggleDisplay
*/
toggleDisplay() {
if (this.player_.tech && this.player_.tech['featuresNativeTextTracks']) {
this.hide();
@ -62,18 +74,34 @@ class TextTrackDisplay extends Component {
}
}
/**
* Create the component's DOM element
*
* @return {Element}
* @method createEl
*/
createEl() {
return super.createEl('div', {
className: 'vjs-text-track-display'
});
}
/**
* Clear display texttracks
*
* @method clearDisplay
*/
clearDisplay() {
if (typeof window['WebVTT'] === 'function') {
window['WebVTT']['processCues'](window, [], this.el_);
}
}
/**
* Update display texttracks
*
* @method updateDisplay
*/
updateDisplay() {
var tracks = this.player_.textTracks();
@ -91,6 +119,12 @@ class TextTrackDisplay extends Component {
}
}
/**
* Add texttrack to texttrack list
*
* @param {TextTrackObject} track Texttrack object to be added to list
* @method updateForTrack
*/
updateForTrack(track) {
if (typeof window['WebVTT'] !== 'function' || !track['activeCues']) {
return;
@ -165,7 +199,14 @@ class TextTrackDisplay extends Component {
}
// Add cue HTML to display
/**
* Add cue HTML to display
*
* @param {Number} color Hex number for color, like #f0e
* @param {Number} opacity Value for opacity,0.0 - 1.0
* @return {RGBAColor} In the form 'rgba(255, 0, 0, 0.3)'
* @method constructColor
*/
function constructColor(color, opacity) {
return 'rgba(' +
// color looks like "#f0e"
@ -175,8 +216,17 @@ function constructColor(color, opacity) {
opacity + ')';
}
/**
* Try to update style
* Some style changes will throw an error, particularly in IE8. Those should be noops.
*
* @param {Element} el The element to be styles
* @param {CSSProperty} style The CSS property to be styled
* @param {CSSStyle} rule The actual style to be applied to the property
* @method tryUpdateStyle
*/
function tryUpdateStyle(el, style, rule) {
// some style changes will throw an error, particularly in IE8. Those should be noops.
//
try {
el.style[style] = rule;
} catch (e) {}

View File

@ -1,4 +1,6 @@
/*
/**
* @file text-track-enums.js
*
* https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackmode
*
* enum TextTrackMode { "disabled", "hidden", "showing" };

View File

@ -1,3 +1,6 @@
/**
* @file text-track-list.js
*/
import EventEmitter from '../event-emitter';
import * as Fn from '../utils/fn.js';
import * as browser from '../utils/browser.js';
@ -52,7 +55,7 @@ TextTrackList.prototype.constructor = TextTrackList;
* change - One or more tracks in the track list have been enabled or disabled.
* addtrack - A track has been added to the track list.
* removetrack - A track has been removed from the track list.
*/
*/
TextTrackList.prototype.allowedEvents_ = {
'change': 'change',
'addtrack': 'addtrack',

View File

@ -1,3 +1,6 @@
/**
* @file text-track-settings.js
*/
import Component from '../component';
import * as Events from '../utils/events.js';
import * as Fn from '../utils/fn.js';
@ -5,6 +8,14 @@ import log from '../utils/log.js';
import safeParseTuple from 'safe-json-parse/tuple';
import window from 'global/window';
/**
* Manipulate settings of texttracks
*
* @param {Object} player Main Player
* @param {Object=} options Object of option names and values
* @extends Component
* @class TextTrackSettings
*/
class TextTrackSettings extends Component {
constructor(player, options) {
@ -49,6 +60,12 @@ class TextTrackSettings extends Component {
}
}
/**
* Create the component's DOM element
*
* @return {Element}
* @method createEl
*/
createEl() {
return super.createEl('div', {
className: 'vjs-caption-settings vjs-modal-overlay',
@ -56,6 +73,21 @@ class TextTrackSettings extends Component {
});
}
/**
* Get texttrack settings
* Settings are
* .vjs-edge-style
* .vjs-font-family
* .vjs-fg-color
* .vjs-text-opacity
* .vjs-bg-color
* .vjs-bg-opacity
* .window-color
* .vjs-window-opacity
*
* @return {Object}
* @method getValues
*/
getValues() {
const el = this.el();
@ -88,6 +120,21 @@ class TextTrackSettings extends Component {
return result;
}
/**
* Set texttrack settings
* Settings are
* .vjs-edge-style
* .vjs-font-family
* .vjs-fg-color
* .vjs-text-opacity
* .vjs-bg-color
* .vjs-bg-opacity
* .window-color
* .vjs-window-opacity
*
* @param {Object} values Object with texttrack setting values
* @method setValues
*/
setValues(values) {
const el = this.el();
@ -109,6 +156,11 @@ class TextTrackSettings extends Component {
setSelectedOption(el.querySelector('.vjs-font-percent > select'), fontPercent);
}
/**
* Restore texttrack settings
*
* @method restoreSettings
*/
restoreSettings() {
let [err, values] = safeParseTuple(window.localStorage.getItem('vjs-text-track-settings'));
@ -121,6 +173,11 @@ class TextTrackSettings extends Component {
}
}
/**
* Save texttrack settings to local storage
*
* @method saveSettings
*/
saveSettings() {
if (!this.options_.persistTextTrackSettings) {
return;
@ -136,6 +193,11 @@ class TextTrackSettings extends Component {
} catch (e) {}
}
/**
* Update display of texttrack settings
*
* @method updateDisplay
*/
updateDisplay() {
let ttDisplay = this.player_.getChild('textTrackDisplay');
if (ttDisplay) {

View File

@ -1,3 +1,6 @@
/**
* @file text-track.js
*/
import TextTrackCueList from './text-track-cue-list';
import * as Fn from '../utils/fn.js';
import * as Guid from '../utils/guid.js';
@ -225,8 +228,8 @@ TextTrack.prototype.removeCue = function(removeCue) {
};
/*
* Downloading stuff happens below this point
*/
* Downloading stuff happens below this point
*/
var parseCues = function(srcContent, track) {
if (typeof window['WebVTT'] !== 'function') {
//try again a bit later

View File

@ -1,10 +1,14 @@
/**
* @file browser.js
*/
import document from 'global/document';
import window from 'global/window';
const USER_AGENT = window.navigator.userAgent;
/**
/*
* Device is an iPhone
*
* @type {Boolean}
* @constant
* @private

View File

@ -1,11 +1,16 @@
/**
* @file buffer.js
*/
import { createTimeRange } from './time-ranges.js';
/**
* Compute how much your video has been buffered
*
* @param {Object} Buffered object
* @param {Number} Total duration
* @return {Number} Percent buffered of the total duration
* @private
* @function bufferedPercent
*/
export function bufferedPercent(buffered, duration) {
var bufferedDuration = 0,

View File

@ -1,13 +1,18 @@
/**
* @file dom.js
*/
import document from 'global/document';
import window from 'global/window';
import * as Guid from './guid.js';
import * as Guid from './guid.js';
import roundFloat from './round-float.js';
/**
* Shorthand for document.getElementById()
* Also allows for CSS (jQuery) ID syntax. But nothing other than IDs.
*
* @param {String} id Element ID
* @return {Element} Element with supplied ID
* @function getEl
*/
export function getEl(id){
if (id.indexOf('#') === 0) {
@ -19,9 +24,11 @@ export function getEl(id){
/**
* Creates an element and applies properties.
*
* @param {String=} tagName Name of tag to be created.
* @param {Object=} properties Element properties to be applied.
* @return {Element}
* @function createEl
*/
export function createEl(tagName='div', properties={}){
let el = document.createElement(tagName);
@ -32,10 +39,10 @@ export function createEl(tagName='div', properties={}){
// Not remembering why we were checking for dash
// but using setAttribute means you have to use getAttribute
// The check for dash checks for the aria-* attributes, like aria-label, aria-valuemin.
// The check for dash checks for the aria- * attributes, like aria-label, aria-valuemin.
// The additional check for "role" is because the default method for adding attributes does not
// add the attribute "role". My guess is because it's not a valid attribute in some namespaces, although
// browsers handle the attribute just fine. The W3C allows for aria-* attributes to be used in pre-HTML5 docs.
// browsers handle the attribute just fine. The W3C allows for aria- * attributes to be used in pre-HTML5 docs.
// http://www.w3.org/TR/wai-aria-primer/#ariahtml. Using setAttribute gets around this problem.
if (propName.indexOf('aria-') !== -1 || propName === 'role') {
el.setAttribute(propName, val);
@ -49,9 +56,11 @@ export function createEl(tagName='div', properties={}){
/**
* Insert an element as the first child node of another
*
* @param {Element} child Element to insert
* @param {[type]} parent Element to insert child into
* @param {Element} parent Element to insert child into
* @private
* @function insertElFirst
*/
export function insertElFirst(child, parent){
if (parent.firstChild) {
@ -65,13 +74,15 @@ export function insertElFirst(child, parent){
* Element Data Store. Allows for binding data to an element without putting it directly on the element.
* Ex. Event listeners are stored here.
* (also from jsninja.com, slightly modified and updated for closure compiler)
*
* @type {Object}
* @private
*/
const elData = {};
/**
/*
* Unique attribute name to store an element's guid in
*
* @type {String}
* @constant
* @private
@ -80,8 +91,10 @@ const elIdAttr = 'vdata' + (new Date()).getTime();
/**
* Returns the cache object where data for an element is stored
*
* @param {Element} el Element to store data for.
* @return {Object}
* @function getElData
*/
export function getElData(el) {
let id = el[elIdAttr];
@ -99,9 +112,11 @@ export function getElData(el) {
/**
* Returns whether or not an element has cached data
*
* @param {Element} el A dom element
* @return {Boolean}
* @private
* @function hasElData
*/
export function hasElData(el) {
const id = el[elIdAttr];
@ -115,8 +130,10 @@ export function hasElData(el) {
/**
* Delete data for the element from the cache and the guid attr from getElementById
*
* @param {Element} el Remove data for an element
* @private
* @function removeElData
*/
export function removeElData(el) {
let id = el[elIdAttr];
@ -143,8 +160,10 @@ export function removeElData(el) {
/**
* Check if an element has a CSS class
*
* @param {Element} element Element to check
* @param {String} classToCheck Classname to check
* @function hasElClass
*/
export function hasElClass(element, classToCheck) {
return ((' ' + element.className + ' ').indexOf(' ' + classToCheck + ' ') !== -1);
@ -152,8 +171,10 @@ export function hasElClass(element, classToCheck) {
/**
* Add a CSS class name to an element
*
* @param {Element} element Element to add class name to
* @param {String} classToAdd Classname to add
* @function addElClass
*/
export function addElClass(element, classToAdd) {
if (!hasElClass(element, classToAdd)) {
@ -163,8 +184,10 @@ export function addElClass(element, classToAdd) {
/**
* Remove a CSS class name from an element
*
* @param {Element} element Element to remove from class name
* @param {String} classToAdd Classname to remove
* @param {String} classToRemove Classname to remove
* @function removeElClass
*/
export function removeElClass(element, classToRemove) {
if (!hasElClass(element, classToRemove)) {return;}
@ -183,9 +206,11 @@ export function removeElClass(element, classToRemove) {
/**
* Apply attributes to an HTML element.
*
* @param {Element} el Target element.
* @param {Object=} attributes Element attributes to be applied.
* @private
* @function setElAttributes
*/
export function setElAttributes(el, attributes) {
Object.getOwnPropertyNames(attributes).forEach(function(attrName){
@ -204,9 +229,11 @@ export function setElAttributes(el, attributes) {
* Attributes are not the same as properties. They're defined on the tag
* or with setAttribute (which shouldn't be used with HTML)
* This will return true or false for boolean attributes.
*
* @param {Element} tag Element from which to get tag attributes
* @return {Object}
* @private
* @function getElAttributes
*/
export function getElAttributes(tag) {
var obj, knownBooleans, attrs, attrName, attrVal;
@ -241,7 +268,12 @@ export function getElAttributes(tag) {
return obj;
}
// Attempt to block the ability to select text while dragging controls
/**
* Attempt to block the ability to select text while dragging controls
*
* @return {Boolean}
* @method blockTextSelection
*/
export function blockTextSelection() {
document.body.focus();
document.onselectstart = function() {
@ -249,15 +281,27 @@ export function blockTextSelection() {
};
}
// Turn off text selection blocking
/**
* Turn off text selection blocking
*
* @return {Boolean}
* @method unblockTextSelection
*/
export function unblockTextSelection() {
document.onselectstart = function() {
return true;
};
}
// Offset Left
// getBoundingClientRect technique from John Resig http://ejohn.org/blog/getboundingclientrect-is-awesome/
/**
* Offset Left
* getBoundingClientRect technique from
* John Resig http://ejohn.org/blog/getboundingclientrect-is-awesome/
*
* @param {Element} el Element from which to get offset
* @return {Object=}
* @method findElPosition
*/
export function findElPosition(el) {
let box;

View File

@ -1,12 +1,14 @@
/**
* @fileoverview Event System (John Resig - Secrets of a JS Ninja http://jsninja.com/)
* @file events.js
*
* Event System (John Resig - Secrets of a JS Ninja http://jsninja.com/)
* (Original book version wasn't completely usable, so fixed some things and made Closure Compiler compatible)
* This should work very similarly to jQuery's events, however it's based off the book version which isn't as
* robust as jquery's, so there's probably some differences.
*/
import * as Dom from './dom.js';
import * as Guid from './guid.js';
import * as Dom from './dom.js';
import * as Guid from './guid.js';
import window from 'global/window';
import document from 'global/document';
@ -15,9 +17,11 @@ import document from 'global/document';
* It stores the handler function in a separate cache object
* and adds a generic handler to the element's event,
* along with a unique id (guid) to the element.
*
* @param {Element|Object} elem Element or object to bind listeners to
* @param {String|Array} type Type of event to bind to.
* @param {Function} fn Event listener.
* @method on
*/
export function on(elem, type, fn){
if (Array.isArray(type)) {
@ -71,9 +75,11 @@ export function on(elem, type, fn){
/**
* Removes event listeners from an element
*
* @param {Element|Object} elem Object to remove listeners from
* @param {String|Array=} type Type of listener to remove. Don't include to remove all events from element.
* @param {Function} fn Specific listener to remove. Don't include to remove listeners for an event type.
* @method off
*/
export function off(elem, type, fn) {
// Don't want to add a cache object through getElData if not needed
@ -125,9 +131,12 @@ export function off(elem, type, fn) {
/**
* Trigger an event for an element
*
* @param {Element|Object} elem Element to trigger an event on
* @param {Event|Object|String} event A string (the type) or an event object with a type attribute
* @param {Object} [hash] data hash to pass along with the event
* @return {Boolean=} Returned only if default was prevented
* @method trigger
*/
export function trigger(elem, event, hash) {
// Fetches element data and a reference to the parent (for bubbling).
@ -178,9 +187,11 @@ export function trigger(elem, event, hash) {
/**
* Trigger a listener only once for an event
*
* @param {Element|Object} elem Element or object to
* @param {String|Array} type
* @param {Function} fn
* @param {String|Array} type Name/type of event
* @param {Function} fn Event handler function
* @method one
*/
export function one(elem, type, fn) {
if (Array.isArray(type)) {
@ -197,9 +208,11 @@ export function one(elem, type, fn) {
/**
* Fix a native event to have standard property values
*
* @param {Object} event Event object to fix
* @return {Object}
* @private
* @method fixEvent
*/
export function fixEvent(event) {
@ -307,9 +320,11 @@ export function fixEvent(event) {
/**
* Clean up the listener cache and dispatchers
*
* @param {Element|Object} elem Element to clean up
* @param {String} type Type of event to clean up
* @private
* @method _cleanUpEvents
*/
function _cleanUpEvents(elem, type) {
var data = Dom.getElData(elem);
@ -343,11 +358,13 @@ function _cleanUpEvents(elem, type) {
/**
* Loops through an array of event types and calls the requested method for each type.
*
* @param {Function} fn The event method we want to use.
* @param {Element|Object} elem Element or object to bind listeners to
* @param {String} type Type of event to bind to.
* @param {Function} callback Event listener.
* @private
* @function _handleMultipleEvents
*/
function _handleMultipleEvents(fn, elem, types, callback) {
types.forEach(function(type) {

View File

@ -1,13 +1,18 @@
/**
* @file fn.js
*/
import { newGUID } from './guid.js';
/**
* Bind (a.k.a proxy or Context). A simple method for changing the context of a function
It also stores a unique id on the function so it can be easily removed from events
* It also stores a unique id on the function so it can be easily removed from events
*
* @param {*} context The object to bind as scope
* @param {Function} fn The function to be bound to a scope
* @param {Number=} uid An optional unique ID for the function to be set
* @return {Function}
* @private
* @method bind
*/
export const bind = function(context, fn, uid) {
// Make sure the function has a unique ID

View File

@ -1,11 +1,15 @@
/**
* @file format-time.js
*
* Format seconds as a time string, H:MM:SS or M:SS
* Supplying a guide (in seconds) will force a number of leading zeros
* to cover the length of the guide
*
* @param {Number} seconds Number of seconds to be turned into a string
* @param {Number} guide Number (in seconds) to model the string after
* @return {String} Time formatted as H:MM:SS or M:SS
* @private
* @function formatTime
*/
function formatTime(seconds, guide=seconds) {
let s = Math.floor(seconds % 60);

View File

@ -1,4 +1,6 @@
/**
* @file guid.js
*
* Unique ID for an element or function
* @type {Number}
* @private
@ -7,6 +9,9 @@ let _guid = 1;
/**
* Get the next unique ID
*
* @return {String}
* @function newGUID
*/
export function newGUID() {
return _guid++;

View File

@ -1,3 +1,6 @@
/**
* @file log.js
*/
import window from 'global/window';
/**
@ -31,8 +34,9 @@ log.warn = function(){
* Log messages to the console and history based on the type of message
*
* @param {String} type The type of message, or `null` for `log`
* @param {[type]} args The args to be passed to the log
* @param {Object} args The args to be passed to the log
* @private
* @method _logType
*/
function _logType(type, args){
// convert args to an array to get array functions

View File

@ -1,3 +1,6 @@
/**
* @file merge-options.js
*/
import merge from 'lodash-compat/object/merge';
function isPlain(obj) {
@ -8,13 +11,13 @@ function isPlain(obj) {
}
/**
* Merge two options objects, recursively merging **only** plain object
* Merge two options objects, recursively merging **only* * plain object
* properties. Previously `deepMerge`.
*
* @param {Object} object The destination object
* @param {...Object} source One or more objects to merge into the first
*
* @returns {Object} The updated first object
* @function mergeOptions
*/
export default function mergeOptions(object={}) {

View File

@ -1,9 +1,13 @@
/**
* @file round-float.js
*
* Should round off a number to a decimal place
*
* @param {Number} num Number to round
* @param {Number} dec Number of decimal places to round to
* @return {Number} Rounded number
* @private
* @method roundFloat
*/
const roundFloat = function(num, dec=0) {
return Math.round(num*Math.pow(10,dec))/Math.pow(10,dec);

View File

@ -1,12 +1,16 @@
/**
* @file time-ranges.js
*
* Should create a fake TimeRange object
* Mimics an HTML5 time range instance, which has functions that
* return the start and end times for a range
* TimeRanges are returned by the buffered() method
*
* @param {Number} start Start time in seconds
* @param {Number} end End time in seconds
* @return {Object} Fake TimeRange object
* @private
* @method createTimeRange
*/
export function createTimeRange(start, end){
if (start === undefined && end === undefined) {

View File

@ -1,8 +1,12 @@
/**
* @file to-title-case.js
*
* Uppercase the first letter of a string
*
* @param {String} string String to be uppercased
* @return {String}
* @private
* @method toTitleCase
*/
function toTitleCase(string){
return string.charAt(0).toUpperCase() + string.slice(1);

View File

@ -1,9 +1,14 @@
/**
* @file url.js
*/
import document from 'global/document';
/**
* Resolve and parse the elements of a URL
*
* @param {String} url The url to parse
* @return {Object} An object of url details
* @method parseUrl
*/
export const parseUrl = function(url) {
const props = ['protocol', 'hostname', 'port', 'pathname', 'search', 'hash', 'host'];
@ -53,9 +58,11 @@ export const parseUrl = function(url) {
/**
* Get absolute version of relative URL. Used to tell flash correct URL.
* http://stackoverflow.com/questions/470832/getting-an-absolute-url-from-a-relative-one-ie6-issue
*
* @param {String} url URL to make absolute
* @return {String} Absolute URL
* @private
* @method getAbsoluteURL
*/
export const getAbsoluteURL = function(url){
// Check if absolute URL
@ -74,6 +81,7 @@ export const getAbsoluteURL = function(url){
*
* @param {String} path The fileName path like '/path/to/file.mp4'
* @returns {String} The extension in lower case or an empty string if no extension could be found.
* @method getFileExtension
*/
export const getFileExtension = function(path) {
if(typeof path === 'string'){

View File

@ -1,3 +1,6 @@
/**
* @file video.js
*/
import document from 'global/document';
import * as setup from './setup';
import Component from './component';
@ -27,16 +30,17 @@ if (typeof HTMLVideoElement === 'undefined') {
/**
* Doubles as the main function for users to create a player instance and also
* the main library object.
*
* The `videojs` function can be used to initialize or retrieve a player.
*
* ```js
* var myPlayer = videojs('my_video_id');
* ```
*
* @param {String|Element} id Video element or video element ID
* @param {Object=} options Optional options object for config/settings
* @param {Function=} ready Optional ready callback
* @return {Player} A player instance
* @namespace
* @return {Player} A player instance
* @mixes videojs
* @method videojs
*/
var videojs = function(id, options, ready){
var tag; // Element of ID
@ -88,8 +92,9 @@ var videojs = function(id, options, ready){
// You have to wait at least once in case this script is loaded after your video in the DOM (weird behavior only with minified version)
setup.autoSetupTimeout(1, videojs);
/**
/*
* Current software version (semver)
*
* @type {String}
*/
videojs.VERSION = '__VERSION__';
@ -97,22 +102,26 @@ videojs.VERSION = '__VERSION__';
/**
* Get the global options object
*
* @returns {Object} The global options object
* @return {Object} The global options object
* @mixes videojs
* @method getGlobalOptions
*/
videojs.getGlobalOptions = () => globalOptions;
/**
* Set options that will apply to every player
*
* ```js
* videojs.setGlobalOptions({
* autoplay: true
* });
* // -> all players will autoplay by default
*
* ```
* NOTE: This will do a deep merge with the new options,
* not overwrite the entire global options object.
*
* @returns {Object} The updated global options object
* @return {Object} The updated global options object
* @mixes videojs
* @method setGlobalOptions
*/
videojs.setGlobalOptions = function(newOptions) {
return mergeOptions(globalOptions, newOptions);
@ -121,7 +130,9 @@ videojs.setGlobalOptions = function(newOptions) {
/**
* Get an object with the currently created players, keyed by player ID
*
* @returns {Object} The created players
* @return {Object} The created players
* @mixes videojs
* @method getPlayers
*/
videojs.getPlayers = function() {
return Player.players;
@ -129,47 +140,49 @@ videojs.getPlayers = function() {
/**
* Get a component class object by name
*
* ```js
* var VjsButton = videojs.getComponent('Button');
*
* // Create a new instance of the component
* var myButton = new VjsButton(myPlayer);
* ```
*
* @return {Component} Component identified by name
* @mixes videojs
* @method getComponent
*/
videojs.getComponent = Component.getComponent;
/**
* Register a component so it can referred to by name
*
* Used when adding to other
* components, either through addChild
* `component.addChild('myComponent')`
* or through default children options
* `{ children: ['myComponent'] }`.
*
* ```js
* // Get a component to subclass
* var VjsButton = videojs.getComponent('Button');
*
* // Subclass the component (see 'extends' doc for more info)
* var MySpecialButton = videojs.extends(VjsButton, {});
*
* // Register the new component
* VjsButton.registerComponent('MySepcialButton', MySepcialButton);
*
* // (optionally) add the new component as a default player child
* myPlayer.addChild('MySepcialButton');
*
* ```
* NOTE: You could also just initialize the component before adding.
* `component.addChild(new MyComponent());`
*
* @param {String} The class name of the component
* @param {Component} The component class
* @returns {Component} The newly registered component
* @return {Component} The newly registered component
* @mixes videojs
* @method registerComponent
*/
videojs.registerComponent = Component.registerComponent;
/**
/*
* A suite of browser and device tests
*
* @type {Object}
*/
videojs.browser = browser;
@ -177,18 +190,16 @@ videojs.browser = browser;
/**
* Subclass an existing class
* Mimics ES6 subclassing with the `extends` keyword
*
* ```js
* // Create a basic javascript 'class'
* function MyClass(name){
* // Set a property at initialization
* this.myName = name;
* }
*
* // Create an instance method
* MyClass.prototype.sayMyName = function(){
* alert(this.myName);
* };
*
* // Subclass the exisitng class and change the name
* // when initializing
* var MySubClass = videojs.extends(MyClass, {
@ -197,16 +208,17 @@ videojs.browser = browser;
* MyClass.call(this, name)
* }
* });
*
* // Create an instance of the new sub class
* var myInstance = new MySubClass('John');
* myInstance.sayMyName(); // -> should alert "John"
* ```
*
* @param {Function} The Class to subclass
* @param {Object} An object including instace methods for the new class
* Optionally including a `constructor` function
*
* @returns {Function} The newly created subclass
* @return {Function} The newly created subclass
* @mixes videojs
* @method extends
*/
videojs.extends = extendsFn;
@ -215,7 +227,7 @@ videojs.extends = extendsFn;
* Performs a deep merge like lodash.merge but **only merges plain objects**
* (not arrays, elements, anything else)
* Other values will be copied directly from the second object.
*
* ```js
* var defaultOptions = {
* foo: true,
* bar: {
@ -229,29 +241,29 @@ videojs.extends = extendsFn;
* b: [4,5,6]
* }
* };
*
* var result = videojs.mergeOptions(defaultOptions, newOptions);
* // result.foo = false;
* // result.bar.a = true;
* // result.bar.b = [4,5,6];
* ```
*
* @param {Object} The options object whose values will be overriden
* @param {Object} The options object with values to override the first
* @param {Object} Any number of additional options objects
*
* @returns {Object} a new object with the merged values
* @return {Object} a new object with the merged values
* @mixes videojs
* @method mergeOptions
*/
videojs.mergeOptions = mergeOptions;
/**
* Create a Video.js player plugin
*
* Plugins are only initialized when options for the plugin are included
* in the player options, or the plugin function on the player instance is
* called.
*
* **See the plugin guide in the docs for a more detailed example**
*
* ```js
* // Make a plugin that alerts when the player plays
* videojs.plugin('myPlugin', function(myPluginOptions) {
* myPluginOptions = myPluginOptions || {};
@ -263,9 +275,7 @@ videojs.mergeOptions = mergeOptions;
* alert(alertText);
* });
* });
*
* // USAGE EXAMPLES
*
* // EXAMPLE 1: New player with plugin options, call plugin immediately
* var player1 = videojs('idOne', {
* myPlugin: {
@ -274,7 +284,6 @@ videojs.mergeOptions = mergeOptions;
* });
* // Click play
* // --> Should alert 'Custom text!'
*
* // EXAMPLE 3: New player, initialize plugin later
* var player3 = videojs('idThree');
* // Click play
@ -286,21 +295,26 @@ videojs.mergeOptions = mergeOptions;
* });
* // Click play
* // --> Should alert 'Plugin added later!'
* ```
*
* @param {String} The plugin name
* @param {Function} The plugin function that will be called with options
* @mixes videojs
* @method plugin
*/
videojs.plugin = plugin;
/**
* Adding languages so that they're available to all players.
*
* ```js
* videojs.addLanguage('es', { 'Hello': 'Hola' });
* ```
*
* @param {String} code The language code or dictionary property
* @param {Object} data The data values to be translated
*
* @return {Object} The resulting language dictionary object
* @mixes videojs
* @method addLanguage
*/
videojs.addLanguage = function(code, data){
code = ('' + code).toLowerCase();
@ -324,7 +338,7 @@ videojs.addLanguage = function(code, data){
// assign(module.exports[name], component);
// });
/**
/*
* Custom Universal Module Definition (UMD)
*
* Video.js will never be a non-browser lib so we can simplify UMD a bunch and

View File

@ -1,13 +1,14 @@
import * as Url from './utils/url.js';
/**
* @file xhr.js
*/
import * as Url from './utils/url.js';
import log from './utils/log.js';
import mergeOptions from './utils/merge-options.js';
import window from 'global/window';
/**
/*
* Simple http request for retrieving external files (e.g. text tracks)
*
* ##### Example
*
* // using url string
* videojs.xhr('http://example.com/myfile.vtt', function(error, response, responseBody){});
*
@ -23,15 +24,15 @@ import window from 'global/window';
* // successful, do something with the response
* }
* });
*
*
* /////////////
* API is modeled after the Raynos/xhr, which we hope to use after
* getting browserify implemented.
* https://github.com/Raynos/xhr/blob/master/index.js
*
* @param {Object|String} options Options block or URL string
* @param {Function} callback The callback function
* @returns {Object} The request
* @return {Object} The request
* @method xhr
*/
var xhr = function(options, callback){
let abortTimeout;
@ -46,7 +47,7 @@ var xhr = function(options, callback){
// Merge with default options
mergeOptions({
method: 'GET',
timeout: 45 * 1000
timeout: 45 * 1000
}, options);
callback = callback || function(){};