diff --git a/.jshintrc b/.jshintrc
deleted file mode 100644
index 826ec9ffb2..0000000000
--- a/.jshintrc
+++ /dev/null
@@ -1,47 +0,0 @@
-{
- "evil" : true,
- "validthis": true,
- "node" : true,
- "debug" : true,
- "boss" : true,
- "expr" : true,
- "eqnull" : true,
- "quotmark" : "single",
- "sub" : true,
- "trailing" : true,
- "undef" : true,
- "laxbreak" : true,
- "esnext" : true,
- "eqeqeq" : true,
- "predef" : [
- "_V_",
- "goog",
- "console",
-
- "require",
- "define",
- "module",
- "exports",
- "process",
-
- "q",
- "asyncTest",
- "deepEqual",
- "equal",
- "expect",
- "module",
- "notDeepEqual",
- "notEqual",
- "notStrictEqual",
- "ok",
- "throws",
- "QUnit",
- "raises",
- "start",
- "stop",
- "strictEqual",
- "test",
- "throws",
- "sinon"
- ]
-}
diff --git a/build/grunt.js b/build/grunt.js
index 379a815ac2..7372c7530b 100644
--- a/build/grunt.js
+++ b/build/grunt.js
@@ -114,14 +114,6 @@ module.exports = function(grunt) {
build: ['build/temp/*'],
dist: ['dist/*']
},
- jshint: {
- src: {
- src: ['src/js/**/*.js', 'Gruntfile.js', 'test/unit/**/*.js'],
- options: {
- jshintrc: '.jshintrc'
- }
- }
- },
uglify: {
options: {
sourceMap: true,
@@ -160,10 +152,6 @@ module.exports = function(grunt) {
skin: {
files: ['src/css/**/*'],
tasks: ['sass']
- },
- jshint: {
- files: ['src/**/*', 'test/unit/**/*.js', 'Gruntfile.js'],
- tasks: 'jshint'
}
},
connect: {
@@ -443,6 +431,14 @@ module.exports = function(grunt) {
src: ['build/temp/video.js']
}
}
+ },
+ shell: {
+ lint: {
+ command: 'vjsstandard',
+ options: {
+ preferLocal: true
+ }
+ }
}
});
@@ -455,7 +451,6 @@ module.exports = function(grunt) {
const buildDependents = [
'clean:build',
- 'jshint',
'browserify:build',
'exorcise:build',
'concat:novtt',
diff --git a/package.json b/package.json
index 892c4090cf..a44ed8387f 100644
--- a/package.json
+++ b/package.json
@@ -14,6 +14,7 @@
"homepage": "http://videojs.com",
"author": "Steve Heffernan",
"scripts": {
+ "lint": "vjsstandard",
"test": "grunt test"
},
"repository": {
@@ -57,7 +58,6 @@
"grunt-contrib-connect": "~0.7.1",
"grunt-contrib-copy": "^0.8.0",
"grunt-contrib-cssmin": "~0.6.0",
- "grunt-contrib-jshint": "~0.11.3",
"grunt-contrib-less": "~0.6.4",
"grunt-contrib-uglify": "^0.8.0",
"grunt-contrib-watch": "~0.1.4",
@@ -66,6 +66,7 @@
"grunt-fastly": "^0.1.3",
"grunt-github-releaser": "^0.1.17",
"grunt-karma": "^0.8.3",
+ "grunt-shell": "^1.3.0",
"grunt-version": "~0.3.0",
"grunt-videojs-languages": "0.0.4",
"grunt-zip": "0.10.2",
@@ -87,9 +88,10 @@
"sinon": "^1.16.1",
"time-grunt": "^1.1.1",
"uglify-js": "~2.3.6",
- "videojs-doc-generator": "0.0.1"
+ "videojs-doc-generator": "0.0.1",
+ "videojs-standard": "^5.0.0"
},
- "standard": {
+ "vjsstandard": {
"ignore": [
"**/Gruntfile.js",
"**/build/**",
@@ -97,7 +99,9 @@
"**/docs/**",
"**/lang/**",
"**/sandbox/**",
- "**/test/**"
+ "**/test/api/**",
+ "**/test/coverage/**",
+ "**/test/karma.conf.js"
]
}
}
diff --git a/src/js/base-styles.js b/src/js/base-styles.js
index be6e302393..cd6ff7a128 100644
--- a/src/js/base-styles.js
+++ b/src/js/base-styles.js
@@ -6,13 +6,17 @@
import window from 'global/window';
import document from 'global/document';
-if (window.VIDEOJS_NO_BASE_THEME) return;
+if (window.VIDEOJS_NO_BASE_THEME) {
+ return;
+}
const styles = '{{GENERATED_STYLES}}';
-if (styles === '{{GENERATED'+'_STYLES}}');
+// Don't think we need this as it's a noop?
+// if (styles === '{{GENERATED'+'_STYLES}}');
const styleNode = document.createElement('style');
+
styleNode.innerHTML = styles;
document.head.insertBefore(styleNode, document.head.firstChild);
diff --git a/src/js/button.js b/src/js/button.js
index 54067cc02c..c869de906f 100644
--- a/src/js/button.js
+++ b/src/js/button.js
@@ -3,10 +3,7 @@
*/
import ClickableComponent from './clickable-component.js';
import Component from './component';
-import * as Events from './utils/events.js';
-import * as Fn from './utils/fn.js';
import log from './utils/log.js';
-import document from 'global/document';
import assign from 'object.assign';
/**
@@ -32,7 +29,7 @@ class Button extends ClickableComponent {
* @return {Element}
* @method createEl
*/
- createEl(tag='button', props={}, attributes={}) {
+ createEl(tag = 'button', props = {}, attributes = {}) {
props = assign({
className: this.buildCSSClass()
}, props);
@@ -53,8 +50,12 @@ class Button extends ClickableComponent {
// Add attributes for button element
attributes = assign({
- type: 'button', // Necessary since the default button type is "submit"
- 'aria-live': 'polite' // let the screen reader user know that the text of the button may change
+
+ // Necessary since the default button type is "submit"
+ 'type': 'button',
+
+ // let the screen reader user know that the text of the button may change
+ 'aria-live': 'polite'
}, attributes);
let el = Component.prototype.createEl.call(this, tag, props, attributes);
@@ -73,8 +74,9 @@ class Button extends ClickableComponent {
* @deprecated
* @method addChild
*/
- addChild(child, options={}) {
+ addChild(child, options = {}) {
let className = this.constructor.name;
+
log.warn(`Adding an actionable (user controllable) child to a Button (${className}) is not supported; use a ClickableComponent instead.`);
// Avoid the error message generated by ClickableComponent's addChild method
@@ -87,13 +89,15 @@ class Button extends ClickableComponent {
* @method handleKeyPress
*/
handleKeyPress(event) {
+
// Ignore Space (32) or Enter (13) key operation, which is handled by the browser for a button.
if (event.which === 32 || event.which === 13) {
- } else {
- super.handleKeyPress(event); // Pass keypress handling up for unsupported keys
+ return;
}
- }
+ // Pass keypress handling up for unsupported keys
+ super.handleKeyPress(event);
+ }
}
Component.registerComponent('Button', Button);
diff --git a/src/js/clickable-component.js b/src/js/clickable-component.js
index 2861b3a228..7d9774a792 100644
--- a/src/js/clickable-component.js
+++ b/src/js/clickable-component.js
@@ -39,7 +39,7 @@ class ClickableComponent extends Component {
* @return {Element}
* @method createEl
*/
- createEl(tag='div', props={}, attributes={}) {
+ createEl(tag = 'div', props = {}, attributes = {}) {
props = assign({
className: this.buildCSSClass(),
tabIndex: 0
@@ -51,8 +51,10 @@ class ClickableComponent extends Component {
// Add ARIA attributes for clickable element which is not a native HTML button
attributes = assign({
- role: 'button',
- 'aria-live': 'polite' // let the screen reader user know that the text of the element may change
+ 'role': 'button',
+
+ // let the screen reader user know that the text of the element may change
+ 'aria-live': 'polite'
}, attributes);
let el = super.createEl(tag, props, attributes);
@@ -91,9 +93,11 @@ class ClickableComponent extends Component {
* @return {String}
* @method controlText
*/
- controlText(text, el=this.el()) {
- if (!text) return this.controlText_ || 'Need Text';
-
+ controlText(text, el = this.el()) {
+ if (!text) {
+ return this.controlText_ || 'Need Text';
+ }
+
const localizedText = this.localize(text);
this.controlText_ = text;
@@ -121,14 +125,14 @@ class ClickableComponent extends Component {
* @return {Component} The child component (created by this process if a string was used)
* @method addChild
*/
- addChild(child, options={}) {
+ addChild(child, options = {}) {
// TODO: Fix adding an actionable child to a ClickableComponent; currently
// it will cause issues with assistive technology (e.g. screen readers)
// which support ARIA, since an element with role="button" cannot have
// actionable child elements.
- //let className = this.constructor.name;
- //log.warn(`Adding a child to a ClickableComponent (${className}) can cause issues with assistive technology which supports ARIA, since an element with role="button" cannot have actionable child elements.`);
+ // let className = this.constructor.name;
+ // log.warn(`Adding a child to a ClickableComponent (${className}) can cause issues with assistive technology which supports ARIA, since an element with role="button" cannot have actionable child elements.`);
return super.addChild(child, options);
}
@@ -179,12 +183,15 @@ class ClickableComponent extends Component {
* @method handleKeyPress
*/
handleKeyPress(event) {
+
// Support Space (32) or Enter (13) key operation to fire a click event
if (event.which === 32 || event.which === 13) {
event.preventDefault();
this.handleClick(event);
} else if (super.handleKeyPress) {
- super.handleKeyPress(event); // Pass keypress handling up for unsupported keys
+
+ // Pass keypress handling up for unsupported keys
+ super.handleKeyPress(event);
}
}
diff --git a/src/js/component.js b/src/js/component.js
index 9ef9d0caf3..18b1f2e95e 100644
--- a/src/js/component.js
+++ b/src/js/component.js
@@ -3,7 +3,6 @@
*
* Player Component - Base class for all UI objects
*/
-
import window from 'global/window';
import * as Dom from './utils/dom.js';
import * as Fn from './utils/fn.js';
@@ -14,7 +13,6 @@ import toTitleCase from './utils/to-title-case.js';
import assign from 'object.assign';
import mergeOptions from './utils/merge-options.js';
-
/**
* Base UI Component class
* Components are embeddable UI objects that are represented by both a
@@ -32,7 +30,7 @@ import mergeOptions from './utils/merge-options.js';
* ```
* Components are also event targets.
* ```js
- * button.on('click', function(){
+ * button.on('click', function() {
* console.log('Button Clicked!');
* });
* button.trigger('customevent');
@@ -340,7 +338,7 @@ class Component {
* @return {Component} The child component (created by this process if a string was used)
* @method addChild
*/
- addChild(child, options={}, index=this.children_.length) {
+ addChild(child, options = {}, index = this.children_.length) {
let component;
let componentName;
@@ -408,6 +406,7 @@ class Component {
if (typeof component.el === 'function' && component.el()) {
let childNodes = this.contentEl().children;
let refNode = childNodes[index] || null;
+
this.contentEl().insertBefore(component.el(), refNode);
}
@@ -540,6 +539,7 @@ class Component {
// If two of the same component are used, different names should be supplied
// for each
let newChild = this.addChild(name, opts);
+
if (newChild) {
this[name] = newChild;
}
@@ -563,13 +563,13 @@ class Component {
return !workingChildren.some(function(wchild) {
if (typeof wchild === 'string') {
return child === wchild;
- } else {
- return child === wchild.name;
}
+ return child === wchild.name;
});
}))
.map((child) => {
- let name, opts;
+ let name;
+ let opts;
if (typeof child === 'string') {
name = child;
@@ -587,6 +587,7 @@ class Component {
// See https://github.com/videojs/video.js/issues/2772
let c = Component.getComponent(child.opts.componentClass ||
toTitleCase(child.name));
+
return c && !Tech.isTech(c);
})
.forEach(handleAdd);
@@ -608,7 +609,7 @@ class Component {
/**
* Add an event listener to this component's element
* ```js
- * var myFunc = function(){
+ * var myFunc = function() {
* var myComponent = this;
* // Do something when the event is fired
* };
@@ -797,7 +798,7 @@ class Component {
* @return {Component}
* @method ready
*/
- ready(fn, sync=false) {
+ ready(fn, sync = false) {
if (fn) {
if (this.isReady_) {
if (sync) {
@@ -824,14 +825,14 @@ class Component {
this.isReady_ = true;
// Ensure ready is triggerd asynchronously
- this.setTimeout(function(){
+ this.setTimeout(function() {
let readyQueue = this.readyQueue_;
// Reset Ready Queue
this.readyQueue_ = [];
if (readyQueue && readyQueue.length > 0) {
- readyQueue.forEach(function(fn){
+ readyQueue.forEach(function(fn) {
fn.call(this);
}, this);
}
@@ -1106,11 +1107,13 @@ class Component {
if (typeof window.getComputedStyle === 'function') {
const computedStyle = window.getComputedStyle(this.el_);
+
computedWidthOrHeight = computedStyle.getPropertyValue(widthOrHeight) || computedStyle[widthOrHeight];
} else if (this.el_.currentStyle) {
// ie 8 doesn't support computed style, shim it
// return clientWidth or clientHeight instead for better accuracy
const rule = `offset${toTitleCase(widthOrHeight)}`;
+
computedWidthOrHeight = this.el_[rule];
}
@@ -1194,7 +1197,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;
diff --git a/src/js/control-bar/audio-track-controls/audio-track-button.js b/src/js/control-bar/audio-track-controls/audio-track-button.js
index b4f7d5575a..3b84c3db6b 100644
--- a/src/js/control-bar/audio-track-controls/audio-track-button.js
+++ b/src/js/control-bar/audio-track-controls/audio-track-button.js
@@ -3,7 +3,6 @@
*/
import TrackButton from '../track-button.js';
import Component from '../../component.js';
-import * as Fn from '../../utils/fn.js';
import AudioTrackMenuItem from './audio-track-menu-item.js';
/**
@@ -40,19 +39,19 @@ class AudioTrackButton extends TrackButton {
* @method createItems
*/
createItems(items = []) {
- let tracks = this.player_.audioTracks && this.player_.audioTracks();
+ const tracks = this.player_.audioTracks && this.player_.audioTracks();
if (!tracks) {
return items;
}
for (let i = 0; i < tracks.length; i++) {
- let track = tracks[i];
+ const track = tracks[i];
items.push(new AudioTrackMenuItem(this.player_, {
+ track,
// MenuItem is selectable
- 'selectable': true,
- 'track': track
+ selectable: true
}));
}
diff --git a/src/js/control-bar/audio-track-controls/audio-track-menu-item.js b/src/js/control-bar/audio-track-controls/audio-track-menu-item.js
index fcaf428a43..b97f44a22f 100644
--- a/src/js/control-bar/audio-track-controls/audio-track-menu-item.js
+++ b/src/js/control-bar/audio-track-controls/audio-track-menu-item.js
@@ -15,8 +15,8 @@ import * as Fn from '../../utils/fn.js';
*/
class AudioTrackMenuItem extends MenuItem {
constructor(player, options) {
- let track = options.track;
- let tracks = player.audioTracks();
+ const track = options.track;
+ const tracks = player.audioTracks();
// Modify options for parent MenuItem class's init.
options.label = track.label || track.language || 'Unknown';
@@ -27,7 +27,7 @@ class AudioTrackMenuItem extends MenuItem {
this.track = track;
if (tracks) {
- let changeHandler = Fn.bind(this, this.handleTracksChange);
+ const changeHandler = Fn.bind(this, this.handleTracksChange);
tracks.addEventListener('change', changeHandler);
this.on('dispose', () => {
@@ -42,14 +42,16 @@ class AudioTrackMenuItem extends MenuItem {
* @method handleClick
*/
handleClick(event) {
- let tracks = this.player_.audioTracks();
+ const tracks = this.player_.audioTracks();
super.handleClick(event);
- if (!tracks) return;
+ if (!tracks) {
+ return;
+ }
for (let i = 0; i < tracks.length; i++) {
- let track = tracks[i];
+ const track = tracks[i];
if (track === this.track) {
track.enabled = true;
diff --git a/src/js/control-bar/control-bar.js b/src/js/control-bar/control-bar.js
index 1fbc82abd6..90d110f696 100644
--- a/src/js/control-bar/control-bar.js
+++ b/src/js/control-bar/control-bar.js
@@ -4,24 +4,24 @@
import Component from '../component.js';
// Required children
-import PlayToggle from './play-toggle.js';
-import CurrentTimeDisplay from './time-controls/current-time-display.js';
-import DurationDisplay from './time-controls/duration-display.js';
-import TimeDivider from './time-controls/time-divider.js';
-import RemainingTimeDisplay from './time-controls/remaining-time-display.js';
-import LiveDisplay from './live-display.js';
-import ProgressControl from './progress-control/progress-control.js';
-import FullscreenToggle from './fullscreen-toggle.js';
-import VolumeControl from './volume-control/volume-control.js';
-import VolumeMenuButton from './volume-menu-button.js';
-import MuteToggle from './mute-toggle.js';
-import ChaptersButton from './text-track-controls/chapters-button.js';
-import DescriptionsButton from './text-track-controls/descriptions-button.js';
-import SubtitlesButton from './text-track-controls/subtitles-button.js';
-import CaptionsButton from './text-track-controls/captions-button.js';
-import AudioTrackButton from './audio-track-controls/audio-track-button.js';
-import PlaybackRateMenuButton from './playback-rate-menu/playback-rate-menu-button.js';
-import CustomControlSpacer from './spacer-controls/custom-control-spacer.js';
+import './play-toggle.js';
+import './time-controls/current-time-display.js';
+import './time-controls/duration-display.js';
+import './time-controls/time-divider.js';
+import './time-controls/remaining-time-display.js';
+import './live-display.js';
+import './progress-control/progress-control.js';
+import './fullscreen-toggle.js';
+import './volume-control/volume-control.js';
+import './volume-menu-button.js';
+import './mute-toggle.js';
+import './text-track-controls/chapters-button.js';
+import './text-track-controls/descriptions-button.js';
+import './text-track-controls/subtitles-button.js';
+import './text-track-controls/captions-button.js';
+import './audio-track-controls/audio-track-button.js';
+import './playback-rate-menu/playback-rate-menu-button.js';
+import './spacer-controls/custom-control-spacer.js';
/**
* Container of main controls
@@ -42,7 +42,8 @@ class ControlBar extends Component {
className: 'vjs-control-bar',
dir: 'ltr'
}, {
- 'role': 'group' // The control bar is a group, so it can contain menuitems
+ // The control bar is a group, so it can contain menuitems
+ role: 'group'
});
}
}
diff --git a/src/js/control-bar/live-display.js b/src/js/control-bar/live-display.js
index 25fd01710b..017b5d0576 100644
--- a/src/js/control-bar/live-display.js
+++ b/src/js/control-bar/live-display.js
@@ -27,7 +27,7 @@ class LiveDisplay extends Component {
* @method createEl
*/
createEl() {
- var el = super.createEl('div', {
+ const el = super.createEl('div', {
className: 'vjs-live-control vjs-control'
});
diff --git a/src/js/control-bar/mute-toggle.js b/src/js/control-bar/mute-toggle.js
index aa063ecc23..16adb66b1b 100644
--- a/src/js/control-bar/mute-toggle.js
+++ b/src/js/control-bar/mute-toggle.js
@@ -21,14 +21,15 @@ class MuteToggle extends Button {
this.on(player, 'volumechange', this.update);
// hide mute toggle if the current tech doesn't support volume control
- if (player.tech_ && player.tech_['featuresVolumeControl'] === false) {
+ if (player.tech_ && player.tech_.featuresVolumeControl === false) {
this.addClass('vjs-hidden');
}
this.on(player, 'loadstart', function() {
- this.update(); // We need to update the button to account for a default muted state.
+ // We need to update the button to account for a default muted state.
+ this.update();
- if (player.tech_['featuresVolumeControl'] === false) {
+ if (player.tech_.featuresVolumeControl === false) {
this.addClass('vjs-hidden');
} else {
this.removeClass('vjs-hidden');
@@ -52,7 +53,7 @@ class MuteToggle extends Button {
* @method handleClick
*/
handleClick() {
- this.player_.muted( this.player_.muted() ? false : true );
+ this.player_.muted(this.player_.muted() ? false : true);
}
/**
@@ -61,8 +62,8 @@ class MuteToggle extends Button {
* @method update
*/
update() {
- var vol = this.player_.volume(),
- level = 3;
+ const vol = this.player_.volume();
+ let level = 3;
if (vol === 0 || this.player_.muted()) {
level = 0;
@@ -75,13 +76,14 @@ class MuteToggle extends Button {
// Don't rewrite the button text if the actual text doesn't change.
// This causes unnecessary and confusing information for screen reader users.
// This check is needed because this function gets called every time the volume level is changed.
- let toMute = this.player_.muted() ? 'Unmute' : 'Mute';
+ const toMute = this.player_.muted() ? 'Unmute' : 'Mute';
+
if (this.controlText() !== toMute) {
this.controlText(toMute);
}
- /* TODO improve muted icon classes */
- for (var i = 0; i < 4; i++) {
+ // TODO improve muted icon classes
+ for (let i = 0; i < 4; i++) {
Dom.removeElClass(this.el_, `vjs-vol-${i}`);
}
Dom.addElClass(this.el_, `vjs-vol-${level}`);
diff --git a/src/js/control-bar/play-toggle.js b/src/js/control-bar/play-toggle.js
index 5849d7808a..3781d135d4 100644
--- a/src/js/control-bar/play-toggle.js
+++ b/src/js/control-bar/play-toggle.js
@@ -14,7 +14,7 @@ import Component from '../component.js';
*/
class PlayToggle extends Button {
- constructor(player, options){
+ constructor(player, options) {
super(player, options);
this.on(player, 'play', this.handlePlay);
@@ -52,7 +52,8 @@ class PlayToggle extends Button {
handlePlay() {
this.removeClass('vjs-paused');
this.addClass('vjs-playing');
- this.controlText('Pause'); // change the button text to "Pause"
+ // change the button text to "Pause"
+ this.controlText('Pause');
}
/**
@@ -63,7 +64,8 @@ class PlayToggle extends Button {
handlePause() {
this.removeClass('vjs-playing');
this.addClass('vjs-paused');
- this.controlText('Play'); // change the button text to "Play"
+ // change the button text to "Play"
+ this.controlText('Play');
}
}
diff --git a/src/js/control-bar/playback-rate-menu/playback-rate-menu-button.js b/src/js/control-bar/playback-rate-menu/playback-rate-menu-button.js
index 342c0aec16..993e94fdf2 100644
--- a/src/js/control-bar/playback-rate-menu/playback-rate-menu-button.js
+++ b/src/js/control-bar/playback-rate-menu/playback-rate-menu-button.js
@@ -17,7 +17,7 @@ import * as Dom from '../../utils/dom.js';
*/
class PlaybackRateMenuButton extends MenuButton {
- constructor(player, options){
+ constructor(player, options) {
super(player, options);
this.updateVisibility();
@@ -34,7 +34,7 @@ class PlaybackRateMenuButton extends MenuButton {
* @method createEl
*/
createEl() {
- let el = super.createEl();
+ const el = super.createEl();
this.labelEl_ = Dom.createEl('div', {
className: 'vjs-playback-rate-value',
@@ -63,13 +63,13 @@ class PlaybackRateMenuButton extends MenuButton {
* @method createMenu
*/
createMenu() {
- let menu = new Menu(this.player());
- let rates = this.playbackRates();
+ const menu = new Menu(this.player());
+ const rates = this.playbackRates();
if (rates) {
for (let i = rates.length - 1; i >= 0; i--) {
menu.addChild(
- new PlaybackRateMenuItem(this.player(), { 'rate': rates[i] + 'x'})
+ new PlaybackRateMenuItem(this.player(), {rate: rates[i] + 'x'})
);
}
}
@@ -94,12 +94,13 @@ class PlaybackRateMenuButton extends MenuButton {
*/
handleClick() {
// select next rate option
- let currentRate = this.player().playbackRate();
- let rates = this.playbackRates();
+ const currentRate = this.player().playbackRate();
+ const rates = this.playbackRates();
// this will select first one if the last one currently selected
let newRate = rates[0];
- for (let i = 0; i < rates.length ; i++) {
+
+ for (let i = 0; i < rates.length; i++) {
if (rates[i] > currentRate) {
newRate = rates[i];
break;
@@ -115,7 +116,7 @@ class PlaybackRateMenuButton extends MenuButton {
* @method playbackRates
*/
playbackRates() {
- return this.options_['playbackRates'] || (this.options_.playerOptions && this.options_.playerOptions['playbackRates']);
+ return this.options_.playbackRates || (this.options_.playerOptions && this.options_.playerOptions.playbackRates);
}
/**
@@ -126,10 +127,10 @@ class PlaybackRateMenuButton extends MenuButton {
* @method playbackRateSupported
*/
playbackRateSupported() {
- return this.player().tech_
- && this.player().tech_['featuresPlaybackRate']
- && this.playbackRates()
- && this.playbackRates().length > 0
+ return this.player().tech_ &&
+ this.player().tech_.featuresPlaybackRate &&
+ this.playbackRates() &&
+ this.playbackRates().length > 0
;
}
diff --git a/src/js/control-bar/playback-rate-menu/playback-rate-menu-item.js b/src/js/control-bar/playback-rate-menu/playback-rate-menu-item.js
index 614d8c1cdb..6ec35dac4f 100644
--- a/src/js/control-bar/playback-rate-menu/playback-rate-menu-item.js
+++ b/src/js/control-bar/playback-rate-menu/playback-rate-menu-item.js
@@ -14,13 +14,13 @@ import Component from '../../component.js';
*/
class PlaybackRateMenuItem extends MenuItem {
- constructor(player, options){
- let label = options['rate'];
- let rate = parseFloat(label, 10);
+ constructor(player, options) {
+ const label = options.rate;
+ const rate = parseFloat(label, 10);
// Modify options for parent MenuItem class's init.
- options['label'] = label;
- options['selected'] = rate === 1;
+ options.label = label;
+ options.selected = rate === 1;
super(player, options);
this.label = label;
diff --git a/src/js/control-bar/progress-control/load-progress-bar.js b/src/js/control-bar/progress-control/load-progress-bar.js
index ec20e8afff..2e1a8aae1c 100644
--- a/src/js/control-bar/progress-control/load-progress-bar.js
+++ b/src/js/control-bar/progress-control/load-progress-bar.js
@@ -14,7 +14,7 @@ import * as Dom from '../../utils/dom.js';
*/
class LoadProgressBar extends Component {
- constructor(player, options){
+ constructor(player, options) {
super(player, options);
this.on(player, 'progress', this.update);
}
@@ -38,14 +38,16 @@ class LoadProgressBar extends Component {
* @method update
*/
update() {
- let buffered = this.player_.buffered();
- let duration = this.player_.duration();
- let bufferedEnd = this.player_.bufferedEnd();
- let children = this.el_.children;
+ const buffered = this.player_.buffered();
+ const duration = this.player_.duration();
+ const bufferedEnd = this.player_.bufferedEnd();
+ const children = this.el_.children;
// get the percent width of a time compared to the total end
- let percentify = function (time, end){
- let percent = (time / end) || 0; // no NaN
+ const percentify = function(time, end) {
+ // no NaN
+ const percent = (time / end) || 0;
+
return ((percent >= 1 ? 1 : percent) * 100) + '%';
};
@@ -54,8 +56,8 @@ class LoadProgressBar extends Component {
// add child elements to represent the individual buffered time ranges
for (let i = 0; i < buffered.length; i++) {
- let start = buffered.start(i);
- let end = buffered.end(i);
+ const start = buffered.start(i);
+ const end = buffered.end(i);
let part = children[i];
if (!part) {
@@ -69,7 +71,7 @@ class LoadProgressBar extends Component {
// remove unused buffered range elements
for (let i = children.length; i > buffered.length; i--) {
- this.el_.removeChild(children[i-1]);
+ this.el_.removeChild(children[i - 1]);
}
}
diff --git a/src/js/control-bar/progress-control/mouse-time-display.js b/src/js/control-bar/progress-control/mouse-time-display.js
index e59be2caa4..c72d132adf 100644
--- a/src/js/control-bar/progress-control/mouse-time-display.js
+++ b/src/js/control-bar/progress-control/mouse-time-display.js
@@ -55,24 +55,24 @@ class MouseTimeDisplay extends Component {
}
handleMouseMove(event) {
- let duration = this.player_.duration();
- let newTime = this.calculateDistance(event) * duration;
- let position = event.pageX - Dom.findElPosition(this.el().parentNode).left;
+ const duration = this.player_.duration();
+ const newTime = this.calculateDistance(event) * duration;
+ const position = event.pageX - Dom.findElPosition(this.el().parentNode).left;
this.update(newTime, position);
}
update(newTime, position) {
- let time = formatTime(newTime, this.player_.duration());
+ const time = formatTime(newTime, this.player_.duration());
this.el().style.left = position + 'px';
this.el().setAttribute('data-current-time', time);
if (this.keepTooltipsInside) {
- let clampedPosition = this.clampPosition_(position);
- let difference = position - clampedPosition + 1;
- let tooltipWidth = parseFloat(window.getComputedStyle(this.tooltip).width);
- let tooltipWidthHalf = tooltipWidth / 2;
+ const clampedPosition = this.clampPosition_(position);
+ const difference = position - clampedPosition + 1;
+ const tooltipWidth = parseFloat(window.getComputedStyle(this.tooltip).width);
+ const tooltipWidthHalf = tooltipWidth / 2;
this.tooltip.innerHTML = time;
this.tooltip.style.right = `-${tooltipWidthHalf - difference}px`;
@@ -98,9 +98,9 @@ class MouseTimeDisplay extends Component {
return position;
}
- let playerWidth = parseFloat(window.getComputedStyle(this.player().el()).width);
- let tooltipWidth = parseFloat(window.getComputedStyle(this.tooltip).width);
- let tooltipWidthHalf = tooltipWidth / 2;
+ const playerWidth = parseFloat(window.getComputedStyle(this.player().el()).width);
+ const tooltipWidth = parseFloat(window.getComputedStyle(this.tooltip).width);
+ const tooltipWidthHalf = tooltipWidth / 2;
let actualPosition = position;
if (position < tooltipWidthHalf) {
diff --git a/src/js/control-bar/progress-control/play-progress-bar.js b/src/js/control-bar/progress-control/play-progress-bar.js
index 7ddea6cf45..5b29ba862a 100644
--- a/src/js/control-bar/progress-control/play-progress-bar.js
+++ b/src/js/control-bar/progress-control/play-progress-bar.js
@@ -3,7 +3,6 @@
*/
import Component from '../../component.js';
import * as Fn from '../../utils/fn.js';
-import * as Dom from '../../utils/dom.js';
import formatTime from '../../utils/format-time.js';
/**
@@ -16,7 +15,7 @@ import formatTime from '../../utils/format-time.js';
*/
class PlayProgressBar extends Component {
- constructor(player, options){
+ constructor(player, options) {
super(player, options);
this.updateDataAttr();
this.on(player, 'timeupdate', this.updateDataAttr);
@@ -48,7 +47,8 @@ class PlayProgressBar extends Component {
}
updateDataAttr() {
- let time = (this.player_.scrubbing()) ? this.player_.getCache().currentTime : this.player_.currentTime();
+ const time = (this.player_.scrubbing()) ? this.player_.getCache().currentTime : this.player_.currentTime();
+
this.el_.setAttribute('data-current-time', formatTime(time, this.player_.duration()));
}
diff --git a/src/js/control-bar/progress-control/progress-control.js b/src/js/control-bar/progress-control/progress-control.js
index 703989e4db..e142f42e3d 100644
--- a/src/js/control-bar/progress-control/progress-control.js
+++ b/src/js/control-bar/progress-control/progress-control.js
@@ -2,8 +2,9 @@
* @file progress-control.js
*/
import Component from '../../component.js';
-import SeekBar from './seek-bar.js';
-import MouseTimeDisplay from './mouse-time-display.js';
+
+import './seek-bar.js';
+import './mouse-time-display.js';
/**
* The Progress Control component contains the seek bar, load progress,
diff --git a/src/js/control-bar/progress-control/seek-bar.js b/src/js/control-bar/progress-control/seek-bar.js
index 21fdc15adb..8fa34694a6 100644
--- a/src/js/control-bar/progress-control/seek-bar.js
+++ b/src/js/control-bar/progress-control/seek-bar.js
@@ -4,12 +4,12 @@
import window from 'global/window';
import Slider from '../../slider/slider.js';
import Component from '../../component.js';
-import LoadProgressBar from './load-progress-bar.js';
-import PlayProgressBar from './play-progress-bar.js';
-import TooltipProgressBar from './tooltip-progress-bar.js';
import * as Fn from '../../utils/fn.js';
import formatTime from '../../utils/format-time.js';
-import assign from 'object.assign';
+
+import './load-progress-bar.js';
+import './play-progress-bar.js';
+import './tooltip-progress-bar.js';
/**
* Seek Bar and holder for the progress bars
@@ -21,7 +21,7 @@ import assign from 'object.assign';
*/
class SeekBar extends Slider {
- constructor(player, options){
+ constructor(player, options) {
super(player, options);
this.on(player, 'timeupdate', this.updateProgress);
this.on(player, 'ended', this.updateProgress);
@@ -65,9 +65,10 @@ class SeekBar extends Slider {
this.updateAriaAttributes(this.tooltipProgressBar.el_);
this.tooltipProgressBar.el_.style.width = this.bar.el_.style.width;
- let playerWidth = parseFloat(window.getComputedStyle(this.player().el()).width);
- let tooltipWidth = parseFloat(window.getComputedStyle(this.tooltipProgressBar.tooltip).width);
- let tooltipStyle = this.tooltipProgressBar.el().style;
+ const playerWidth = parseFloat(window.getComputedStyle(this.player().el()).width);
+ const tooltipWidth = parseFloat(window.getComputedStyle(this.tooltipProgressBar.tooltip).width);
+ const tooltipStyle = this.tooltipProgressBar.el().style;
+
tooltipStyle.maxWidth = Math.floor(playerWidth - (tooltipWidth / 2)) + 'px';
tooltipStyle.minWidth = Math.ceil(tooltipWidth / 2) + 'px';
tooltipStyle.right = `-${tooltipWidth / 2}px`;
@@ -76,9 +77,12 @@ class SeekBar extends Slider {
updateAriaAttributes(el) {
// Allows for smooth scrubbing, when player can't keep up.
- let time = (this.player_.scrubbing()) ? this.player_.getCache().currentTime : this.player_.currentTime();
- el.setAttribute('aria-valuenow', (this.getPercent() * 100).toFixed(2)); // machine readable value of progress bar (percentage complete)
- el.setAttribute('aria-valuetext', formatTime(time, this.player_.duration())); // human readable value of progress bar (time complete)
+ const time = (this.player_.scrubbing()) ? this.player_.getCache().currentTime : this.player_.currentTime();
+
+ // machine readable value of progress bar (percentage complete)
+ el.setAttribute('aria-valuenow', (this.getPercent() * 100).toFixed(2));
+ // human readable value of progress bar (time complete)
+ el.setAttribute('aria-valuetext', formatTime(time, this.player_.duration()));
}
/**
@@ -88,7 +92,8 @@ class SeekBar extends Slider {
* @method getPercent
*/
getPercent() {
- let percent = this.player_.currentTime() / this.player_.duration();
+ const percent = this.player_.currentTime() / this.player_.duration();
+
return percent >= 1 ? 1 : percent;
}
@@ -115,7 +120,9 @@ class SeekBar extends Slider {
let newTime = this.calculateDistance(event) * this.player_.duration();
// Don't let video end while scrubbing.
- if (newTime === this.player_.duration()) { newTime = newTime - 0.1; }
+ if (newTime === this.player_.duration()) {
+ newTime = newTime - 0.1;
+ }
// Set new time (tell player to seek to new time)
this.player_.currentTime(newTime);
@@ -141,7 +148,8 @@ class SeekBar extends Slider {
* @method stepForward
*/
stepForward() {
- this.player_.currentTime(this.player_.currentTime() + 5); // more quickly fast forward for keyboard-only users
+ // more quickly fast forward for keyboard-only users
+ this.player_.currentTime(this.player_.currentTime() + 5);
}
/**
@@ -150,7 +158,8 @@ class SeekBar extends Slider {
* @method stepBack
*/
stepBack() {
- this.player_.currentTime(this.player_.currentTime() - 5); // more quickly rewind for keyboard-only users
+ // more quickly rewind for keyboard-only users
+ this.player_.currentTime(this.player_.currentTime() - 5);
}
}
@@ -161,7 +170,7 @@ SeekBar.prototype.options_ = {
'mouseTimeDisplay',
'playProgressBar'
],
- 'barName': 'playProgressBar'
+ barName: 'playProgressBar'
};
SeekBar.prototype.playerEvent = 'timeupdate';
diff --git a/src/js/control-bar/progress-control/tooltip-progress-bar.js b/src/js/control-bar/progress-control/tooltip-progress-bar.js
index f1e092dad3..4a6db351ba 100644
--- a/src/js/control-bar/progress-control/tooltip-progress-bar.js
+++ b/src/js/control-bar/progress-control/tooltip-progress-bar.js
@@ -3,7 +3,6 @@
*/
import Component from '../../component.js';
import * as Fn from '../../utils/fn.js';
-import * as Dom from '../../utils/dom.js';
import formatTime from '../../utils/format-time.js';
/**
@@ -16,7 +15,7 @@ import formatTime from '../../utils/format-time.js';
*/
class TooltipProgressBar extends Component {
- constructor(player, options){
+ constructor(player, options) {
super(player, options);
this.updateDataAttr();
this.on(player, 'timeupdate', this.updateDataAttr);
@@ -30,7 +29,7 @@ class TooltipProgressBar extends Component {
* @method createEl
*/
createEl() {
- let el = super.createEl('div', {
+ const el = super.createEl('div', {
className: 'vjs-tooltip-progress-bar vjs-slider-bar',
innerHTML: `
${this.localize('Progress')}: 0%`
@@ -42,8 +41,9 @@ class TooltipProgressBar extends Component {
}
updateDataAttr() {
- let time = (this.player_.scrubbing()) ? this.player_.getCache().currentTime : this.player_.currentTime();
- let formattedTime = formatTime(time, this.player_.duration());
+ const time = (this.player_.scrubbing()) ? this.player_.getCache().currentTime : this.player_.currentTime();
+ const formattedTime = formatTime(time, this.player_.duration());
+
this.el_.setAttribute('data-current-time', formattedTime);
this.tooltip.innerHTML = formattedTime;
}
diff --git a/src/js/control-bar/spacer-controls/custom-control-spacer.js b/src/js/control-bar/spacer-controls/custom-control-spacer.js
index 7327442b4a..a5c5a21f34 100644
--- a/src/js/control-bar/spacer-controls/custom-control-spacer.js
+++ b/src/js/control-bar/spacer-controls/custom-control-spacer.js
@@ -29,8 +29,8 @@ class CustomControlSpacer extends Spacer {
* @method createEl
*/
createEl() {
- let el = super.createEl({
- className: this.buildCSSClass(),
+ const el = super.createEl({
+ className: this.buildCSSClass()
});
// No-flex/table-cell mode requires there be some content
diff --git a/src/js/control-bar/text-track-controls/caption-settings-menu-item.js b/src/js/control-bar/text-track-controls/caption-settings-menu-item.js
index 712543f20b..7632802cb8 100644
--- a/src/js/control-bar/text-track-controls/caption-settings-menu-item.js
+++ b/src/js/control-bar/text-track-controls/caption-settings-menu-item.js
@@ -12,24 +12,24 @@ import Component from '../../component.js';
* @extends TextTrackMenuItem
* @class CaptionSettingsMenuItem
*/
- class CaptionSettingsMenuItem extends TextTrackMenuItem {
+class CaptionSettingsMenuItem extends TextTrackMenuItem {
constructor(player, options) {
- options['track'] = {
- 'kind': options['kind'],
- 'player': player,
- 'label': options['kind'] + ' settings',
- 'selectable': false,
- 'default': false,
+ options.track = {
+ player,
+ kind: options.kind,
+ label: options.kind + ' settings',
+ selectable: false,
+ default: false,
mode: 'disabled'
};
// CaptionSettingsMenuItem has no concept of 'selected'
- options['selectable'] = false;
+ options.selectable = false;
super(player, options);
this.addClass('vjs-texttrack-settings');
- this.controlText(', opens ' + options['kind'] + ' settings dialog');
+ this.controlText(', opens ' + options.kind + ' settings dialog');
}
/**
diff --git a/src/js/control-bar/text-track-controls/captions-button.js b/src/js/control-bar/text-track-controls/captions-button.js
index b5ee37cfc9..929c841022 100644
--- a/src/js/control-bar/text-track-controls/captions-button.js
+++ b/src/js/control-bar/text-track-controls/captions-button.js
@@ -16,9 +16,9 @@ import CaptionSettingsMenuItem from './caption-settings-menu-item.js';
*/
class CaptionsButton extends TextTrackButton {
- constructor(player, options, ready){
+ constructor(player, options, ready) {
super(player, options, ready);
- this.el_.setAttribute('aria-label','Captions Menu');
+ this.el_.setAttribute('aria-label', 'Captions Menu');
}
/**
@@ -38,10 +38,11 @@ class CaptionsButton extends TextTrackButton {
*/
update() {
let threshold = 2;
+
super.update();
// if native, then threshold is 1 because no settings button
- if (this.player().tech_ && this.player().tech_['featuresNativeTextTracks']) {
+ if (this.player().tech_ && this.player().tech_.featuresNativeTextTracks) {
threshold = 1;
}
@@ -59,10 +60,10 @@ class CaptionsButton extends TextTrackButton {
* @method createItems
*/
createItems() {
- let items = [];
+ const items = [];
- if (!(this.player().tech_ && this.player().tech_['featuresNativeTextTracks'])) {
- items.push(new CaptionSettingsMenuItem(this.player_, { 'kind': this.kind_ }));
+ if (!(this.player().tech_ && this.player().tech_.featuresNativeTextTracks)) {
+ items.push(new CaptionSettingsMenuItem(this.player_, {kind: this.kind_}));
}
return super.createItems(items);
diff --git a/src/js/control-bar/text-track-controls/chapters-button.js b/src/js/control-bar/text-track-controls/chapters-button.js
index 0cc8606ea8..004be740d2 100644
--- a/src/js/control-bar/text-track-controls/chapters-button.js
+++ b/src/js/control-bar/text-track-controls/chapters-button.js
@@ -7,9 +7,7 @@ import TextTrackMenuItem from './text-track-menu-item.js';
import ChaptersTrackMenuItem from './chapters-track-menu-item.js';
import Menu from '../../menu/menu.js';
import * as Dom from '../../utils/dom.js';
-import * as Fn from '../../utils/fn.js';
import toTitleCase from '../../utils/to-title-case.js';
-import window from 'global/window';
/**
* The button component for toggling and selecting chapters
@@ -24,9 +22,9 @@ import window from 'global/window';
*/
class ChaptersButton extends TextTrackButton {
- constructor(player, options, ready){
+ constructor(player, options, ready) {
super(player, options, ready);
- this.el_.setAttribute('aria-label','Chapters Menu');
+ this.el_.setAttribute('aria-label', 'Chapters Menu');
}
/**
@@ -46,20 +44,18 @@ class ChaptersButton extends TextTrackButton {
* @method createItems
*/
createItems() {
- let items = [];
-
- let tracks = this.player_.textTracks();
+ const items = [];
+ const tracks = this.player_.textTracks();
if (!tracks) {
return items;
}
for (let i = 0; i < tracks.length; i++) {
- let track = tracks[i];
- if (track['kind'] === this.kind_) {
- items.push(new TextTrackMenuItem(this.player_, {
- 'track': track
- }));
+ const track = tracks[i];
+
+ if (track.kind === this.kind_) {
+ items.push(new TextTrackMenuItem(this.player_, {track}));
}
}
@@ -73,16 +69,16 @@ class ChaptersButton extends TextTrackButton {
* @method createMenu
*/
createMenu() {
- let tracks = this.player_.textTracks() || [];
+ const tracks = this.player_.textTracks() || [];
let chaptersTrack;
let items = this.items || [];
for (let i = tracks.length - 1; i >= 0; i--) {
// We will always choose the last track as our chaptersTrack
- let track = tracks[i];
+ const track = tracks[i];
- if (track['kind'] === this.kind_) {
+ if (track.kind === this.kind_) {
chaptersTrack = track;
break;
@@ -90,27 +86,30 @@ class ChaptersButton extends TextTrackButton {
}
let menu = this.menu;
+
if (menu === undefined) {
menu = new Menu(this.player_);
- let title = Dom.createEl('li', {
+
+ const title = Dom.createEl('li', {
className: 'vjs-menu-title',
innerHTML: toTitleCase(this.kind_),
tabIndex: -1
});
+
menu.children_.unshift(title);
Dom.insertElFirst(title, menu.contentEl());
} else {
- // We will empty out the menu children each time because we want a
- // fresh new menu child list each time
- items.forEach(item => menu.removeChild(item));
- // Empty out the ChaptersButton menu items because we no longer need them
- items = [];
+ // We will empty out the menu children each time because we want a
+ // fresh new menu child list each time
+ items.forEach(item => menu.removeChild(item));
+ // Empty out the ChaptersButton menu items because we no longer need them
+ items = [];
}
- if (chaptersTrack && chaptersTrack.cues == null) {
- chaptersTrack['mode'] = 'hidden';
+ if (chaptersTrack && (chaptersTrack.cues === null || chaptersTrack.cues === undefined)) {
+ chaptersTrack.mode = 'hidden';
- let remoteTextTrackEl = this.player_.remoteTextTrackEls().getTrackElementByTrack_(chaptersTrack);
+ const remoteTextTrackEl = this.player_.remoteTextTrackEls().getTrackElementByTrack_(chaptersTrack);
if (remoteTextTrackEl) {
remoteTextTrackEl.addEventListener('load', (event) => this.update());
@@ -118,14 +117,14 @@ class ChaptersButton extends TextTrackButton {
}
if (chaptersTrack && chaptersTrack.cues && chaptersTrack.cues.length > 0) {
- let cues = chaptersTrack['cues'], cue;
+ const cues = chaptersTrack.cues;
for (let i = 0, l = cues.length; i < l; i++) {
- cue = cues[i];
+ const cue = cues[i];
- let mi = new ChaptersTrackMenuItem(this.player_, {
- 'track': chaptersTrack,
- 'cue': cue
+ const mi = new ChaptersTrackMenuItem(this.player_, {
+ cue,
+ track: chaptersTrack
});
items.push(mi);
diff --git a/src/js/control-bar/text-track-controls/chapters-track-menu-item.js b/src/js/control-bar/text-track-controls/chapters-track-menu-item.js
index 40b717a0e4..2291da4c30 100644
--- a/src/js/control-bar/text-track-controls/chapters-track-menu-item.js
+++ b/src/js/control-bar/text-track-controls/chapters-track-menu-item.js
@@ -15,14 +15,14 @@ import * as Fn from '../../utils/fn.js';
*/
class ChaptersTrackMenuItem extends MenuItem {
- constructor(player, options){
- let track = options['track'];
- let cue = options['cue'];
- let currentTime = player.currentTime();
+ constructor(player, options) {
+ const track = options.track;
+ const cue = options.cue;
+ const currentTime = player.currentTime();
// Modify options for parent MenuItem class's init.
- options['label'] = cue.text;
- options['selected'] = (cue['startTime'] <= currentTime && currentTime < cue['endTime']);
+ options.label = cue.text;
+ options.selected = (cue.startTime <= currentTime && currentTime < cue.endTime);
super(player, options);
this.track = track;
@@ -47,11 +47,11 @@ class ChaptersTrackMenuItem extends MenuItem {
* @method update
*/
update() {
- let cue = this.cue;
- let currentTime = this.player_.currentTime();
+ const cue = this.cue;
+ const currentTime = this.player_.currentTime();
// vjs.log(currentTime, cue.startTime);
- this.selected(cue['startTime'] <= currentTime && currentTime < cue['endTime']);
+ this.selected(cue.startTime <= currentTime && currentTime < cue.endTime);
}
}
diff --git a/src/js/control-bar/text-track-controls/descriptions-button.js b/src/js/control-bar/text-track-controls/descriptions-button.js
index 671c620c56..0b7bd02b45 100644
--- a/src/js/control-bar/text-track-controls/descriptions-button.js
+++ b/src/js/control-bar/text-track-controls/descriptions-button.js
@@ -16,14 +16,14 @@ import * as Fn from '../../utils/fn.js';
*/
class DescriptionsButton extends TextTrackButton {
- constructor(player, options, ready){
+ constructor(player, options, ready) {
super(player, options, ready);
this.el_.setAttribute('aria-label', 'Descriptions Menu');
- let tracks = player.textTracks();
+ const tracks = player.textTracks();
if (tracks) {
- let changeHandler = Fn.bind(this, this.handleTracksChange);
+ const changeHandler = Fn.bind(this, this.handleTracksChange);
tracks.addEventListener('change', changeHandler);
this.on('dispose', function() {
@@ -37,14 +37,15 @@ class DescriptionsButton extends TextTrackButton {
*
* @method handleTracksChange
*/
- handleTracksChange(event){
- let tracks = this.player().textTracks();
+ handleTracksChange(event) {
+ const tracks = this.player().textTracks();
let disabled = false;
// Check whether a track of a different kind is showing
for (let i = 0, l = tracks.length; i < l; i++) {
- let track = tracks[i];
- if (track['kind'] !== this.kind_ && track['mode'] === 'showing') {
+ const track = tracks[i];
+
+ if (track.kind !== this.kind_ && track.mode === 'showing') {
disabled = true;
break;
}
diff --git a/src/js/control-bar/text-track-controls/off-text-track-menu-item.js b/src/js/control-bar/text-track-controls/off-text-track-menu-item.js
index 9cc124b9df..a23b82bd4d 100644
--- a/src/js/control-bar/text-track-controls/off-text-track-menu-item.js
+++ b/src/js/control-bar/text-track-controls/off-text-track-menu-item.js
@@ -14,19 +14,19 @@ import Component from '../../component.js';
*/
class OffTextTrackMenuItem extends TextTrackMenuItem {
- constructor(player, options){
+ constructor(player, options) {
// Create pseudo track info
// Requires options['kind']
- options['track'] = {
- 'kind': options['kind'],
- 'player': player,
- 'label': options['kind'] + ' off',
- 'default': false,
- 'mode': 'disabled'
+ options.track = {
+ player,
+ kind: options.kind,
+ label: options.kind + ' off',
+ default: false,
+ mode: 'disabled'
};
// MenuItem is selectable
- options['selectable'] = true;
+ options.selectable = true;
super(player, options);
this.selected(true);
@@ -38,13 +38,14 @@ class OffTextTrackMenuItem extends TextTrackMenuItem {
* @param {Object} event Event object
* @method handleTracksChange
*/
- handleTracksChange(event){
- let tracks = this.player().textTracks();
+ handleTracksChange(event) {
+ const tracks = this.player().textTracks();
let selected = true;
for (let i = 0, l = tracks.length; i < l; i++) {
- let track = tracks[i];
- if (track['kind'] === this.track['kind'] && track['mode'] === 'showing') {
+ const track = tracks[i];
+
+ if (track.kind === this.track.kind && track.mode === 'showing') {
selected = false;
break;
}
diff --git a/src/js/control-bar/text-track-controls/subtitles-button.js b/src/js/control-bar/text-track-controls/subtitles-button.js
index c56731496e..207e8179d2 100644
--- a/src/js/control-bar/text-track-controls/subtitles-button.js
+++ b/src/js/control-bar/text-track-controls/subtitles-button.js
@@ -15,9 +15,9 @@ import Component from '../../component.js';
*/
class SubtitlesButton extends TextTrackButton {
- constructor(player, options, ready){
+ constructor(player, options, ready) {
super(player, options, ready);
- this.el_.setAttribute('aria-label','Subtitles Menu');
+ this.el_.setAttribute('aria-label', 'Subtitles Menu');
}
/**
diff --git a/src/js/control-bar/text-track-controls/text-track-button.js b/src/js/control-bar/text-track-controls/text-track-button.js
index 1decbeec24..fced8fb3ce 100644
--- a/src/js/control-bar/text-track-controls/text-track-button.js
+++ b/src/js/control-bar/text-track-controls/text-track-button.js
@@ -3,7 +3,6 @@
*/
import TrackButton from '../track-button.js';
import Component from '../../component.js';
-import * as Fn from '../../utils/fn.js';
import TextTrackMenuItem from './text-track-menu-item.js';
import OffTextTrackMenuItem from './off-text-track-menu-item.js';
@@ -17,7 +16,7 @@ import OffTextTrackMenuItem from './off-text-track-menu-item.js';
*/
class TextTrackButton extends TrackButton {
- constructor(player, options = {}){
+ constructor(player, options = {}) {
options.tracks = player.textTracks();
super(player, options);
@@ -29,25 +28,25 @@ class TextTrackButton extends TrackButton {
* @return {Array} Array of menu items
* @method createItems
*/
- createItems(items=[]) {
+ createItems(items = []) {
// Add an OFF menu item to turn all tracks off
- items.push(new OffTextTrackMenuItem(this.player_, { 'kind': this.kind_ }));
+ items.push(new OffTextTrackMenuItem(this.player_, {kind: this.kind_}));
- let tracks = this.player_.textTracks();
+ const tracks = this.player_.textTracks();
if (!tracks) {
return items;
}
for (let i = 0; i < tracks.length; i++) {
- let track = tracks[i];
+ const track = tracks[i];
// only add tracks that are of the appropriate kind and have a label
- if (track['kind'] === this.kind_) {
+ if (track.kind === this.kind_) {
items.push(new TextTrackMenuItem(this.player_, {
+ track,
// MenuItem is selectable
- 'selectable': true,
- 'track': track
+ selectable: true
}));
}
}
diff --git a/src/js/control-bar/text-track-controls/text-track-menu-item.js b/src/js/control-bar/text-track-controls/text-track-menu-item.js
index 8b4c73bdad..ccb5b02010 100644
--- a/src/js/control-bar/text-track-controls/text-track-menu-item.js
+++ b/src/js/control-bar/text-track-controls/text-track-menu-item.js
@@ -17,20 +17,20 @@ import document from 'global/document';
*/
class TextTrackMenuItem extends MenuItem {
- constructor(player, options){
- let track = options['track'];
- let tracks = player.textTracks();
+ constructor(player, options) {
+ const track = options.track;
+ const tracks = player.textTracks();
// Modify options for parent MenuItem class's init.
- options['label'] = track['label'] || track['language'] || 'Unknown';
- options['selected'] = track['default'] || track['mode'] === 'showing';
+ options.label = track.label || track.language || 'Unknown';
+ options.selected = track.default || track.mode === 'showing';
super(player, options);
this.track = track;
if (tracks) {
- let changeHandler = Fn.bind(this, this.handleTracksChange);
+ const changeHandler = Fn.bind(this, this.handleTracksChange);
tracks.addEventListener('change', changeHandler);
this.on('dispose', function() {
@@ -52,7 +52,9 @@ class TextTrackMenuItem extends MenuItem {
// Android 2.3 throws an Illegal Constructor error for window.Event
try {
event = new window.Event('change');
- } catch(err){}
+ } catch (err) {
+ // continue regardless of error
+ }
}
if (!event) {
@@ -71,24 +73,26 @@ class TextTrackMenuItem extends MenuItem {
* @method handleClick
*/
handleClick(event) {
- let kind = this.track['kind'];
- let tracks = this.player_.textTracks();
+ const kind = this.track.kind;
+ const tracks = this.player_.textTracks();
super.handleClick(event);
- if (!tracks) return;
+ if (!tracks) {
+ return;
+ }
for (let i = 0; i < tracks.length; i++) {
- let track = tracks[i];
+ const track = tracks[i];
- if (track['kind'] !== kind) {
+ if (track.kind !== kind) {
continue;
}
if (track === this.track) {
- track['mode'] = 'showing';
+ track.mode = 'showing';
} else {
- track['mode'] = 'disabled';
+ track.mode = 'disabled';
}
}
}
@@ -98,8 +102,8 @@ class TextTrackMenuItem extends MenuItem {
*
* @method handleTracksChange
*/
- handleTracksChange(event){
- this.selected(this.track['mode'] === 'showing');
+ handleTracksChange(event) {
+ this.selected(this.track.mode === 'showing');
}
}
diff --git a/src/js/control-bar/time-controls/current-time-display.js b/src/js/control-bar/time-controls/current-time-display.js
index ff99fc54e6..66a102aeea 100644
--- a/src/js/control-bar/time-controls/current-time-display.js
+++ b/src/js/control-bar/time-controls/current-time-display.js
@@ -15,7 +15,7 @@ import formatTime from '../../utils/format-time.js';
*/
class CurrentTimeDisplay extends Component {
- constructor(player, options){
+ constructor(player, options) {
super(player, options);
this.on(player, 'timeupdate', this.updateContent);
@@ -28,14 +28,14 @@ class CurrentTimeDisplay extends Component {
* @method createEl
*/
createEl() {
- let el = super.createEl('div', {
+ const el = super.createEl('div', {
className: 'vjs-current-time vjs-time-control vjs-control'
});
this.contentEl_ = Dom.createEl('div', {
className: 'vjs-current-time-display',
// label the current time for screen reader users
- innerHTML: 'Current Time ' + '0:00',
+ innerHTML: 'Current Time ' + '0:00'
}, {
// tell screen readers not to automatically read the time as it changes
'aria-live': 'off'
@@ -52,9 +52,10 @@ class CurrentTimeDisplay extends Component {
*/
updateContent() {
// Allows for smooth scrubbing, when player can't keep up.
- let time = (this.player_.scrubbing()) ? this.player_.getCache().currentTime : this.player_.currentTime();
- let localizedText = this.localize('Current Time');
- let formattedTime = formatTime(time, this.player_.duration());
+ const time = (this.player_.scrubbing()) ? this.player_.getCache().currentTime : this.player_.currentTime();
+ const localizedText = this.localize('Current Time');
+ const formattedTime = formatTime(time, this.player_.duration());
+
if (formattedTime !== this.formattedTime_) {
this.formattedTime_ = formattedTime;
this.contentEl_.innerHTML = `${localizedText} ${formattedTime}`;
diff --git a/src/js/control-bar/time-controls/duration-display.js b/src/js/control-bar/time-controls/duration-display.js
index 0496e3cd50..1b2cb27f50 100644
--- a/src/js/control-bar/time-controls/duration-display.js
+++ b/src/js/control-bar/time-controls/duration-display.js
@@ -15,7 +15,7 @@ import formatTime from '../../utils/format-time.js';
*/
class DurationDisplay extends Component {
- constructor(player, options){
+ constructor(player, options) {
super(player, options);
this.on(player, 'durationchange', this.updateContent);
@@ -28,7 +28,7 @@ class DurationDisplay extends Component {
* @method createEl
*/
createEl() {
- let el = super.createEl('div', {
+ const el = super.createEl('div', {
className: 'vjs-duration vjs-time-control vjs-control'
});
@@ -51,12 +51,15 @@ class DurationDisplay extends Component {
* @method updateContent
*/
updateContent() {
- let duration = this.player_.duration();
+ const duration = this.player_.duration();
+
if (duration && this.duration_ !== duration) {
this.duration_ = duration;
- let localizedText = this.localize('Duration Time');
- let formattedTime = formatTime(duration);
- this.contentEl_.innerHTML = `${localizedText} ${formattedTime}`; // label the duration time for screen reader users
+ const localizedText = this.localize('Duration Time');
+ const formattedTime = formatTime(duration);
+
+ // label the duration time for screen reader users
+ this.contentEl_.innerHTML = `${localizedText} ${formattedTime}`;
}
}
diff --git a/src/js/control-bar/time-controls/remaining-time-display.js b/src/js/control-bar/time-controls/remaining-time-display.js
index 8ac701f6b1..40914b7cd1 100644
--- a/src/js/control-bar/time-controls/remaining-time-display.js
+++ b/src/js/control-bar/time-controls/remaining-time-display.js
@@ -15,7 +15,7 @@ import formatTime from '../../utils/format-time.js';
*/
class RemainingTimeDisplay extends Component {
- constructor(player, options){
+ constructor(player, options) {
super(player, options);
this.on(player, 'timeupdate', this.updateContent);
@@ -29,14 +29,14 @@ class RemainingTimeDisplay extends Component {
* @method createEl
*/
createEl() {
- let el = super.createEl('div', {
+ const el = super.createEl('div', {
className: 'vjs-remaining-time vjs-time-control vjs-control'
});
this.contentEl_ = Dom.createEl('div', {
className: 'vjs-remaining-time-display',
// label the remaining time for screen reader users
- innerHTML: `${this.localize('Remaining Time')} -0:00`,
+ innerHTML: `${this.localize('Remaining Time')} -0:00`
}, {
// tell screen readers not to automatically read the time as it changes
'aria-live': 'off'
@@ -55,6 +55,7 @@ class RemainingTimeDisplay extends Component {
if (this.player_.duration()) {
const localizedText = this.localize('Remaining Time');
const formattedTime = formatTime(this.player_.remainingTime());
+
if (formattedTime !== this.formattedTime_) {
this.formattedTime_ = formattedTime;
this.contentEl_.innerHTML = `${localizedText} -${formattedTime}`;
diff --git a/src/js/control-bar/track-button.js b/src/js/control-bar/track-button.js
index f482465fa1..4b3056b1a8 100644
--- a/src/js/control-bar/track-button.js
+++ b/src/js/control-bar/track-button.js
@@ -15,8 +15,8 @@ import * as Fn from '../utils/fn.js';
*/
class TrackButton extends MenuButton {
- constructor(player, options){
- let tracks = options.tracks;
+ constructor(player, options) {
+ const tracks = options.tracks;
super(player, options);
@@ -28,7 +28,8 @@ class TrackButton extends MenuButton {
return;
}
- let updateHandler = Fn.bind(this, this.update);
+ const updateHandler = Fn.bind(this, this.update);
+
tracks.addEventListener('removetrack', updateHandler);
tracks.addEventListener('addtrack', updateHandler);
diff --git a/src/js/control-bar/volume-control/volume-bar.js b/src/js/control-bar/volume-control/volume-bar.js
index bf775cd6cc..db44eb9e59 100644
--- a/src/js/control-bar/volume-control/volume-bar.js
+++ b/src/js/control-bar/volume-control/volume-bar.js
@@ -6,7 +6,7 @@ import Component from '../../component.js';
import * as Fn from '../../utils/fn.js';
// Required children
-import VolumeLevel from './volume-level.js';
+import './volume-level.js';
/**
* The bar that contains the volume level and can be clicked on to adjust the level
@@ -18,7 +18,7 @@ import VolumeLevel from './volume-level.js';
*/
class VolumeBar extends Slider {
- constructor(player, options){
+ constructor(player, options) {
super(player, options);
this.on(player, 'volumechange', this.updateARIAAttributes);
player.ready(Fn.bind(this, this.updateARIAAttributes));
@@ -63,9 +63,8 @@ class VolumeBar extends Slider {
getPercent() {
if (this.player_.muted()) {
return 0;
- } else {
- return this.player_.volume();
}
+ return this.player_.volume();
}
/**
@@ -95,7 +94,8 @@ class VolumeBar extends Slider {
*/
updateARIAAttributes() {
// Current value of volume bar as a percentage
- let volume = (this.player_.volume() * 100).toFixed(2);
+ const volume = (this.player_.volume() * 100).toFixed(2);
+
this.el_.setAttribute('aria-valuenow', volume);
this.el_.setAttribute('aria-valuetext', volume + '%');
}
@@ -106,7 +106,7 @@ VolumeBar.prototype.options_ = {
children: [
'volumeLevel'
],
- 'barName': 'volumeLevel'
+ barName: 'volumeLevel'
};
VolumeBar.prototype.playerEvent = 'volumechange';
diff --git a/src/js/control-bar/volume-control/volume-control.js b/src/js/control-bar/volume-control/volume-control.js
index 2095b3dfac..741b403c17 100644
--- a/src/js/control-bar/volume-control/volume-control.js
+++ b/src/js/control-bar/volume-control/volume-control.js
@@ -4,7 +4,7 @@
import Component from '../../component.js';
// Required children
-import VolumeBar from './volume-bar.js';
+import './volume-bar.js';
/**
* The component for controlling the volume level
@@ -16,15 +16,15 @@ import VolumeBar from './volume-bar.js';
*/
class VolumeControl extends Component {
- constructor(player, options){
+ constructor(player, options) {
super(player, options);
// hide volume controls when they're not supported by the current tech
- if (player.tech_ && player.tech_['featuresVolumeControl'] === false) {
+ if (player.tech_ && player.tech_.featuresVolumeControl === false) {
this.addClass('vjs-hidden');
}
- this.on(player, 'loadstart', function(){
- if (player.tech_['featuresVolumeControl'] === false) {
+ this.on(player, 'loadstart', function() {
+ if (player.tech_.featuresVolumeControl === false) {
this.addClass('vjs-hidden');
} else {
this.removeClass('vjs-hidden');
diff --git a/src/js/control-bar/volume-menu-button.js b/src/js/control-bar/volume-menu-button.js
index 83879ab5f9..d650a245e4 100644
--- a/src/js/control-bar/volume-menu-button.js
+++ b/src/js/control-bar/volume-menu-button.js
@@ -18,7 +18,7 @@ import VolumeBar from './volume-control/volume-bar.js';
*/
class VolumeMenuButton extends PopupButton {
- constructor(player, options={}){
+ constructor(player, options = {}) {
// Default to inline
if (options.inline === undefined) {
options.inline = true;
@@ -48,7 +48,7 @@ class VolumeMenuButton extends PopupButton {
// hide mute toggle if the current tech doesn't support volume control
function updateVisibility() {
- if (player.tech_ && player.tech_['featuresVolumeControl'] === false) {
+ if (player.tech_ && player.tech_.featuresVolumeControl === false) {
this.addClass('vjs-hidden');
} else {
this.removeClass('vjs-hidden');
@@ -58,19 +58,19 @@ class VolumeMenuButton extends PopupButton {
updateVisibility.call(this);
this.on(player, 'loadstart', updateVisibility);
- this.on(this.volumeBar, ['slideractive', 'focus'], function(){
+ this.on(this.volumeBar, ['slideractive', 'focus'], function() {
this.addClass('vjs-slider-active');
});
- this.on(this.volumeBar, ['sliderinactive', 'blur'], function(){
+ this.on(this.volumeBar, ['sliderinactive', 'blur'], function() {
this.removeClass('vjs-slider-active');
});
- this.on(this.volumeBar, ['focus'], function(){
+ this.on(this.volumeBar, ['focus'], function() {
this.addClass('vjs-lock-showing');
});
- this.on(this.volumeBar, ['blur'], function(){
+ this.on(this.volumeBar, ['blur'], function() {
this.removeClass('vjs-lock-showing');
});
}
@@ -83,7 +83,8 @@ class VolumeMenuButton extends PopupButton {
*/
buildCSSClass() {
let orientationClass = '';
- if (!!this.options_.vertical) {
+
+ if (this.options_.vertical) {
orientationClass = 'vjs-volume-menu-button-vertical';
} else {
orientationClass = 'vjs-volume-menu-button-horizontal';
@@ -99,11 +100,11 @@ class VolumeMenuButton extends PopupButton {
* @method createPopup
*/
createPopup() {
- let popup = new Popup(this.player_, {
+ const popup = new Popup(this.player_, {
contentElType: 'div'
});
- let vb = new VolumeBar(this.player_, this.options_.volumeBar);
+ const vb = new VolumeBar(this.player_, this.options_.volumeBar);
popup.addChild(vb);
diff --git a/src/js/error-display.js b/src/js/error-display.js
index 36cde55267..fcdd67c4ef 100644
--- a/src/js/error-display.js
+++ b/src/js/error-display.js
@@ -3,8 +3,6 @@
*/
import Component from './component';
import ModalDialog from './modal-dialog';
-
-import * as Dom from './utils/dom';
import mergeOptions from './utils/merge-options';
/**
@@ -46,6 +44,7 @@ class ErrorDisplay extends ModalDialog {
*/
content() {
let error = this.player().error();
+
return error ? this.localize(error.message) : '';
}
}
diff --git a/src/js/event-target.js b/src/js/event-target.js
index 281d2b99c2..5fe9012583 100644
--- a/src/js/event-target.js
+++ b/src/js/event-target.js
@@ -3,7 +3,7 @@
*/
import * as Events from './utils/events.js';
-var EventTarget = function() {};
+const EventTarget = function() {};
EventTarget.prototype.allowedEvents_ = {};
@@ -11,21 +11,25 @@ EventTarget.prototype.on = function(type, fn) {
// Remove the addEventListener alias before calling Events.on
// so we don't get into an infinite type loop
let ael = this.addEventListener;
+
this.addEventListener = () => {};
Events.on(this, type, fn);
this.addEventListener = ael;
};
+
EventTarget.prototype.addEventListener = EventTarget.prototype.on;
EventTarget.prototype.off = function(type, fn) {
Events.off(this, type, fn);
};
+
EventTarget.prototype.removeEventListener = EventTarget.prototype.off;
EventTarget.prototype.one = function(type, fn) {
// Remove the addEventListener alias before calling Events.on
// so we don't get into an infinite type loop
let ael = this.addEventListener;
+
this.addEventListener = () => {};
Events.one(this, type, fn);
this.addEventListener = ael;
@@ -35,9 +39,7 @@ EventTarget.prototype.trigger = function(event) {
let type = event.type || event;
if (typeof event === 'string') {
- event = {
- type: type
- };
+ event = {type};
}
event = Events.fixEvent(event);
@@ -47,6 +49,7 @@ EventTarget.prototype.trigger = function(event) {
Events.trigger(this, event);
};
+
// The standard DOM EventTarget.dispatchEvent() is aliased to trigger()
EventTarget.prototype.dispatchEvent = EventTarget.prototype.trigger;
diff --git a/src/js/extend.js b/src/js/extend.js
index 963ca2eda2..1d1acfd8fe 100644
--- a/src/js/extend.js
+++ b/src/js/extend.js
@@ -7,7 +7,7 @@ import log from './utils/log';
* Both work the same but node adds `super_` to the subClass
* and Bable adds the superClass as __proto__. Both seem useful.
*/
-const _inherits = function (subClass, superClass) {
+const _inherits = function(subClass, superClass) {
if (typeof superClass !== 'function' && superClass !== null) {
throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass);
}
@@ -44,10 +44,11 @@ const _inherits = function (subClass, superClass) {
* });
* ```
*/
-const extendFn = function(superClass, subClassMethods={}) {
+const extendFn = function(superClass, subClassMethods = {}) {
let subClass = function() {
superClass.apply(this, arguments);
};
+
let methods = {};
if (typeof subClassMethods === 'object') {
@@ -66,7 +67,7 @@ const extendFn = function(superClass, subClassMethods={}) {
_inherits(subClass, superClass);
// Extend subObj's prototype with functions and other properties from props
- for (var name in methods) {
+ for (let name in methods) {
if (methods.hasOwnProperty(name)) {
subClass.prototype[name] = methods[name];
}
diff --git a/src/js/fullscreen-api.js b/src/js/fullscreen-api.js
index b594541ab1..72fa08a626 100644
--- a/src/js/fullscreen-api.js
+++ b/src/js/fullscreen-api.js
@@ -74,7 +74,7 @@ for (let i = 0; i < apiMap.length; i++) {
// map the browser API names to the spec API names
if (browserApi) {
- for (let i=0; i 1) {
data = arguments[1];
}
@@ -1259,15 +1283,17 @@ class Player extends Component {
techCall_(method, arg) {
// If it's not ready yet, call method when it is
if (this.tech_ && !this.tech_.isReady_) {
- this.tech_.ready(function(){
+ this.tech_.ready(function() {
this[method](arg);
}, true);
// Otherwise call method now
} else {
try {
- this.tech_ && this.tech_[method](arg);
- } catch(e) {
+ if (this.tech_) {
+ this.tech_[method](arg);
+ }
+ } catch (e) {
log(e);
throw e;
}
@@ -1290,18 +1316,17 @@ class Player extends Component {
// When that happens we'll catch the errors and inform tech that it's not ready any more.
try {
return this.tech_[method]();
- } catch(e) {
+ } catch (e) {
// When building additional tech libs, an expected method may not be defined yet
if (this.tech_[method] === undefined) {
log(`Video.js: ${method} method not defined for ${this.techName_} playback technology.`, e);
+
+ // When a method isn't available on the object it throws a TypeError
+ } else if (e.name === 'TypeError') {
+ log(`Video.js: ${method} unavailable on ${this.techName_} playback technology element.`, e);
+ this.tech_.isReady_ = false;
} else {
- // When a method isn't available on the object it throws a TypeError
- if (e.name === 'TypeError') {
- log(`Video.js: ${method} unavailable on ${this.techName_} playback technology element.`, e);
- this.tech_.isReady_ = false;
- } else {
- log(e);
- }
+ log(e);
}
throw e;
}
@@ -1414,7 +1439,8 @@ class Player extends Component {
// currentTime when scrubbing, but may not provide much performance benefit afterall.
// Should be tested. Also something has to read the actual current time or the cache will
// never get updated.
- return this.cache_.currentTime = (this.techGet_('currentTime') || 0);
+ this.cache_.currentTime = (this.techGet_('currentTime') || 0);
+ return this.cache_.currentTime;
}
/**
@@ -1495,10 +1521,10 @@ class Player extends Component {
* @method buffered
*/
buffered() {
- var buffered = this.techGet_('buffered');
+ let buffered = this.techGet_('buffered');
if (!buffered || !buffered.length) {
- buffered = createTimeRange(0,0);
+ buffered = createTimeRange(0, 0);
}
return buffered;
@@ -1527,9 +1553,9 @@ class Player extends Component {
* @method bufferedEnd
*/
bufferedEnd() {
- var buffered = this.buffered(),
- duration = this.duration(),
- end = buffered.end(buffered.length-1);
+ let buffered = this.buffered();
+ let duration = this.duration();
+ let end = buffered.end(buffered.length - 1);
if (end > duration) {
end = duration;
@@ -1557,7 +1583,8 @@ class Player extends Component {
let vol;
if (percentAsDecimal !== undefined) {
- vol = Math.max(0, Math.min(1, parseFloat(percentAsDecimal))); // Force value to between 0 and 1
+ // Force value to between 0 and 1
+ vol = Math.max(0, Math.min(1, parseFloat(percentAsDecimal)));
this.cache_.volume = vol;
this.techCall_('setVolume', vol);
@@ -1569,7 +1596,6 @@ class Player extends Component {
return (isNaN(vol)) ? 1 : vol;
}
-
/**
* Get the current muted state, or turn mute on or off
* ```js
@@ -1589,7 +1615,7 @@ class Player extends Component {
this.techCall_('setMuted', muted);
return this;
}
- return this.techGet_('muted') || false; // Default to false
+ return this.techGet_('muted') || false;
}
// Check if current tech can support native fullscreen
@@ -1645,7 +1671,7 @@ class Player extends Component {
* @method requestFullscreen
*/
requestFullscreen() {
- var fsApi = FullscreenApi;
+ let fsApi = FullscreenApi;
this.isFullscreen(true);
@@ -1658,7 +1684,7 @@ class Player extends Component {
// when canceling fullscreen. Otherwise if there's multiple
// players on a page, they would all be reacting to the same fullscreen
// events
- Events.on(document, fsApi.fullscreenchange, Fn.bind(this, function documentFullscreenChange(e){
+ Events.on(document, fsApi.fullscreenchange, Fn.bind(this, function documentFullscreenChange(e) {
this.isFullscreen(document[fsApi.fullscreenElement]);
// If cancelling fullscreen, remove event listener.
@@ -1695,17 +1721,18 @@ class Player extends Component {
* @method exitFullscreen
*/
exitFullscreen() {
- var fsApi = FullscreenApi;
+ let fsApi = FullscreenApi;
+
this.isFullscreen(false);
// Check for browser element fullscreen support
if (fsApi.requestFullscreen) {
document[fsApi.exitFullscreen]();
} else if (this.tech_.supportsFullScreen()) {
- this.techCall_('exitFullScreen');
+ this.techCall_('exitFullScreen');
} else {
- this.exitFullWindow();
- this.trigger('fullscreenchange');
+ this.exitFullWindow();
+ this.trigger('fullscreenchange');
}
return this;
@@ -1845,7 +1872,7 @@ class Player extends Component {
// Iterate over each `innerArray` element once per `outerArray` element and execute
// `tester` with both. If `tester` returns a non-falsy value, exit early and return
// that value.
- let findFirstPassingTechSourcePair = function (outerArray, innerArray, tester) {
+ let findFirstPassingTechSourcePair = function(outerArray, innerArray, tester) {
let found;
outerArray.some((outerChoice) => {
@@ -1865,7 +1892,7 @@ class Player extends Component {
let flip = (fn) => (a, b) => fn(b, a);
let finder = ([techName, tech], source) => {
if (tech.canPlaySource(source, this.options_[techName.toLowerCase()])) {
- return {source: source, tech: techName};
+ return {source, tech: techName};
}
};
@@ -1920,6 +1947,7 @@ class Player extends Component {
}
let currentTech = Tech.getTech(this.techName_);
+
// Support old behavior of techs being registered as components.
// Remove once that deprecated behavior is removed.
if (!currentTech) {
@@ -1948,7 +1976,7 @@ class Player extends Component {
this.currentType_ = source.type || '';
// wait until the tech is ready to set the source
- this.ready(function(){
+ this.ready(function() {
// The setSource tech method was added with source handlers
// so older techs won't support it
@@ -1984,7 +2012,7 @@ class Player extends Component {
* @method sourceList_
*/
sourceList_(sources) {
- var sourceTech = this.selectSource(sources);
+ let sourceTech = this.selectSource(sources);
if (sourceTech) {
if (sourceTech.tech === this.techName_) {
@@ -1996,7 +2024,7 @@ class Player extends Component {
}
} else {
// We need to wrap this in a timeout to give folks a chance to add error event handlers
- this.setTimeout( function() {
+ this.setTimeout(function() {
this.error({ code: 4, message: this.localize(this.options_.notSupportedMessage) });
}, 0);
@@ -2098,7 +2126,7 @@ class Player extends Component {
loop(value) {
if (value !== undefined) {
this.techCall_('setLoop', value);
- this.options_['loop'] = value;
+ this.options_.loop = value;
return this;
}
return this.techGet_('loop');
@@ -2172,7 +2200,8 @@ class Player extends Component {
*/
controls(bool) {
if (bool !== undefined) {
- bool = !!bool; // force boolean
+ bool = !!bool;
+
// Don't trigger a change event unless it actually changed
if (this.controls_ !== bool) {
this.controls_ = bool;
@@ -2218,7 +2247,8 @@ class Player extends Component {
*/
usingNativeControls(bool) {
if (bool !== undefined) {
- bool = !!bool; // force boolean
+ bool = !!bool;
+
// Don't trigger a change event unless it actually changed
if (this.usingNativeControls_ !== bool) {
this.usingNativeControls_ = bool;
@@ -2302,7 +2332,9 @@ class Player extends Component {
* @return {Boolean} True if the player is in the ended state, false if not.
* @method ended
*/
- ended() { return this.techGet_('ended'); }
+ ended() {
+ return this.techGet_('ended');
+ }
/**
* Returns whether or not the player is in the "seeking" state.
@@ -2310,7 +2342,9 @@ class Player extends Component {
* @return {Boolean} True if the player is in the seeking state, false if not.
* @method seeking
*/
- seeking() { return this.techGet_('seeking'); }
+ seeking() {
+ return this.techGet_('seeking');
+ }
/**
* Returns the TimeRanges of the media that are currently available
@@ -2319,7 +2353,9 @@ class Player extends Component {
* @return {TimeRanges} the seekable intervals of the media timeline
* @method seekable
*/
- seekable() { return this.techGet_('seekable'); }
+ seekable() {
+ return this.techGet_('seekable');
+ }
/**
* Report user activity
@@ -2363,8 +2399,8 @@ class Player extends Component {
//
// When this gets resolved in ALL browsers it can be removed
// https://code.google.com/p/chromium/issues/detail?id=103041
- if(this.tech_) {
- this.tech_.one('mousemove', function(e){
+ if (this.tech_) {
+ this.tech_.one('mousemove', function(e) {
e.stopPropagation();
e.preventDefault();
});
@@ -2387,14 +2423,15 @@ class Player extends Component {
* @method listenForUserActivity_
*/
listenForUserActivity_() {
- let mouseInProgress, lastMoveX, lastMoveY;
-
+ let mouseInProgress;
+ let lastMoveX;
+ let lastMoveY;
let handleActivity = Fn.bind(this, this.reportUserActivity);
let handleMouseMove = function(e) {
// #1068 - Prevent mousemove spamming
// Chrome Bug: https://code.google.com/p/chromium/issues/detail?id=366970
- if(e.screenX !== lastMoveX || e.screenY !== lastMoveY) {
+ if (e.screenX !== lastMoveX || e.screenY !== lastMoveY) {
lastMoveX = e.screenX;
lastMoveY = e.screenY;
handleActivity();
@@ -2435,7 +2472,8 @@ class Player extends Component {
// then gets picked up by this loop
// http://ejohn.org/blog/learning-from-twitter/
let inactivityTimeout;
- let activityCheck = this.setInterval(function() {
+
+ this.setInterval(function() {
// Check to see if mouse/touch activity has happened
if (this.userActivity_) {
// Reset the activity tracker
@@ -2447,16 +2485,17 @@ class Player extends Component {
// Clear any existing inactivity timeout to start the timer over
this.clearTimeout(inactivityTimeout);
- var timeout = this.options_['inactivityTimeout'];
+ let timeout = this.options_.inactivityTimeout;
+
if (timeout > 0) {
// In milliseconds, if no more activity has occurred the
// user will be considered inactive
- inactivityTimeout = this.setTimeout(function () {
+ inactivityTimeout = this.setTimeout(function() {
// Protect against the case where the inactivityTimeout can trigger just
- // before the next user activity is picked up by the activityCheck loop
+ // before the next user activity is picked up by the activity check loop
// causing a flicker
if (!this.userActivity_) {
- this.userActive(false);
+ this.userActive(false);
}
}, timeout);
}
@@ -2481,11 +2520,10 @@ class Player extends Component {
return this;
}
- if (this.tech_ && this.tech_['featuresPlaybackRate']) {
+ if (this.tech_ && this.tech_.featuresPlaybackRate) {
return this.techGet_('playbackRate');
- } else {
- return 1.0;
}
+ return 1.0;
}
/**
@@ -2611,7 +2649,9 @@ class Player extends Component {
textTracks() {
// cannot use techGet_ directly because it checks to see whether the tech is ready.
// Flash is unlikely to be ready in time but textTracks should still work.
- return this.tech_ && this.tech_['textTracks']();
+ if (this.tech_) {
+ return this.tech_.textTracks();
+ }
}
/**
@@ -2621,7 +2661,9 @@ class Player extends Component {
* @method remoteTextTracks
*/
remoteTextTracks() {
- return this.tech_ && this.tech_['remoteTextTracks']();
+ if (this.tech_) {
+ return this.tech_.remoteTextTracks();
+ }
}
/**
@@ -2631,7 +2673,9 @@ class Player extends Component {
* @method remoteTextTrackEls
*/
remoteTextTrackEls() {
- return this.tech_ && this.tech_['remoteTextTrackEls']();
+ if (this.tech_) {
+ return this.tech_.remoteTextTrackEls();
+ }
}
/**
@@ -2645,7 +2689,9 @@ class Player extends Component {
* @method addTextTrack
*/
addTextTrack(kind, label, language) {
- return this.tech_ && this.tech_['addTextTrack'](kind, label, language);
+ if (this.tech_) {
+ return this.tech_.addTextTrack(kind, label, language);
+ }
}
/**
@@ -2655,7 +2701,9 @@ class Player extends Component {
* @method addRemoteTextTrack
*/
addRemoteTextTrack(options) {
- return this.tech_ && this.tech_['addRemoteTextTrack'](options);
+ if (this.tech_) {
+ return this.tech_.addRemoteTextTrack(options);
+ }
}
/**
@@ -2666,8 +2714,10 @@ class Player extends Component {
*/
// destructure the input into an object with a track argument, defaulting to arguments[0]
// default the whole argument to an empty object if nothing was passed in
- removeRemoteTextTrack({track = arguments[0]} = {}) { // jshint ignore:line
- this.tech_ && this.tech_['removeRemoteTextTrack'](track);
+ removeRemoteTextTrack({track = arguments[0]} = {}) {
+ if (this.tech_) {
+ return this.tech_.removeRemoteTextTrack(track);
+ }
}
/**
@@ -2691,11 +2741,11 @@ class Player extends Component {
}
// Methods to add support for
- // initialTime: function(){ return this.techCall_('initialTime'); },
- // startOffsetTime: function(){ return this.techCall_('startOffsetTime'); },
- // played: function(){ return this.techCall_('played'); },
- // defaultPlaybackRate: function(){ return this.techCall_('defaultPlaybackRate'); },
- // defaultMuted: function(){ return this.techCall_('defaultMuted'); }
+ // initialTime: function() { return this.techCall_('initialTime'); },
+ // startOffsetTime: function() { return this.techCall_('startOffsetTime'); },
+ // played: function() { return this.techCall_('played'); },
+ // defaultPlaybackRate: function() { return this.techCall_('defaultPlaybackRate'); },
+ // defaultMuted: function() { return this.techCall_('defaultMuted'); }
/**
* The player's language code
@@ -2713,7 +2763,7 @@ class Player extends Component {
return this.language_;
}
- this.language_ = (''+code).toLowerCase();
+ this.language_ = String(code).toLowerCase();
return this;
}
@@ -2726,7 +2776,7 @@ class Player extends Component {
* @method languages
*/
languages() {
- return mergeOptions(Player.prototype.options_.languages, this.languages_);
+ return mergeOptions(Player.prototype.options_.languages, this.languages_);
}
/**
@@ -2770,16 +2820,14 @@ class Player extends Component {
* @return {ModalDialog}
*/
createModal(content, options) {
- let player = this;
-
options = options || {};
options.content = content || '';
- let modal = new ModalDialog(player, options);
+ let modal = new ModalDialog(this, options);
- player.addChild(modal);
- modal.on('dispose', function() {
- player.removeChild(modal);
+ this.addChild(modal);
+ modal.on('dispose', () => {
+ this.removeChild(modal);
});
return modal.open();
@@ -2795,18 +2843,19 @@ class Player extends Component {
*/
static getTagSettings(tag) {
let baseOptions = {
- 'sources': [],
- 'tracks': []
+ sources: [],
+ tracks: []
};
const tagOptions = Dom.getElAttributes(tag);
const dataSetup = tagOptions['data-setup'];
// Check if data-setup attr exists.
- if (dataSetup !== null){
+ if (dataSetup !== null) {
// Parse options JSON
// If empty string, make it a parsable json object.
const [err, data] = safeParseTuple(dataSetup || '{}');
+
if (err) {
log.error(err);
}
@@ -2819,10 +2868,11 @@ class Player extends Component {
if (tag.hasChildNodes()) {
const children = tag.childNodes;
- for (let i=0, j=children.length; i 0) {
- for(let i=0, e=vids.length; i 0) {
- for(let i=0, e=audios.length; i 0) {
- for (let i=0, e=mediaEls.length; i this.play(), 0);
}
}
@@ -188,6 +191,7 @@ class Flash extends Tech {
*/
setCurrentTime(time) {
let seekable = this.seekable();
+
if (seekable.length) {
// clamp to the current seekable range
time = time > seekable.start(0) ? time : seekable.start(0);
@@ -224,9 +228,8 @@ class Flash extends Tech {
currentSrc() {
if (this.currentSource_) {
return this.currentSource_.src;
- } else {
- return this.el_.vjs_getProperty('currentSrc');
}
+ return this.el_.vjs_getProperty('currentSrc');
}
/**
@@ -237,10 +240,10 @@ class Flash extends Tech {
duration() {
if (this.readyState() === 0) {
return NaN;
- } else {
- let duration = this.el_.vjs_getProperty('duration');
- return duration >= 0 ? duration : Infinity;
}
+ let duration = this.el_.vjs_getProperty('duration');
+
+ return duration >= 0 ? duration : Infinity;
}
/**
@@ -276,6 +279,7 @@ class Flash extends Tech {
*/
seekable() {
const duration = this.duration();
+
if (duration === 0) {
return createTimeRange();
}
@@ -290,6 +294,7 @@ class Flash extends Tech {
*/
buffered() {
let ranges = this.el_.vjs_getProperty('buffered');
+
if (ranges.length === 0) {
return createTimeRange();
}
@@ -305,7 +310,8 @@ class Flash extends Tech {
* @method supportsFullScreen
*/
supportsFullScreen() {
- return false; // Flash does not allow fullscreen through javascript
+ // Flash does not allow fullscreen through javascript
+ return false;
}
/**
@@ -322,18 +328,23 @@ class Flash extends Tech {
}
-
// Create setters and getters for attributes
const _api = Flash.prototype;
const _readWrite = 'rtmpConnection,rtmpStream,preload,defaultPlaybackRate,playbackRate,autoplay,loop,mediaGroup,controller,controls,volume,muted,defaultMuted'.split(',');
const _readOnly = 'networkState,readyState,initialTime,startOffsetTime,paused,ended,videoWidth,videoHeight'.split(',');
-function _createSetter(attr){
- var attrUpper = attr.charAt(0).toUpperCase() + attr.slice(1);
- _api['set'+attrUpper] = function(val){ return this.el_.vjs_setProperty(attr, val); };
+function _createSetter(attr) {
+ let attrUpper = attr.charAt(0).toUpperCase() + attr.slice(1);
+
+ _api['set' + attrUpper] = function(val) {
+ return this.el_.vjs_setProperty(attr, val);
+ };
}
+
function _createGetter(attr) {
- _api[attr] = function(){ return this.el_.vjs_getProperty(attr); };
+ _api[attr] = function() {
+ return this.el_.vjs_getProperty(attr);
+ };
}
// Create getter and setters for all read/write attributes
@@ -349,7 +360,7 @@ for (let i = 0; i < _readOnly.length; i++) {
/* Flash Support Testing -------------------------------------------------------- */
-Flash.isSupported = function(){
+Flash.isSupported = function() {
return Flash.version()[0] >= 10;
// return swfobject.hasFlashPlayerVersion('10');
};
@@ -371,7 +382,7 @@ Flash.nativeSourceHandler = {};
* @param {String} type The mimetype to check
* @return {String} 'probably', 'maybe', or '' (empty string)
*/
-Flash.nativeSourceHandler.canPlayType = function(type){
+Flash.nativeSourceHandler.canPlayType = function(type) {
if (type in Flash.formats) {
return 'maybe';
}
@@ -386,11 +397,12 @@ Flash.nativeSourceHandler.canPlayType = function(type){
* @param {Object} options The options passed to the tech
* @return {String} 'probably', 'maybe', or '' (empty string)
*/
-Flash.nativeSourceHandler.canHandleSource = function(source, options){
- var type;
+Flash.nativeSourceHandler.canHandleSource = function(source, options) {
+ let type;
function guessMimeType(src) {
- var ext = Url.getFileExtension(src);
+ let ext = Url.getFileExtension(src);
+
if (ext) {
return `video/${ext}`;
}
@@ -416,7 +428,7 @@ Flash.nativeSourceHandler.canHandleSource = function(source, options){
* @param {Flash} tech The instance of the Flash tech
* @param {Object} options The options to pass to the source
*/
-Flash.nativeSourceHandler.handleSource = function(source, tech, options){
+Flash.nativeSourceHandler.handleSource = function(source, tech, options) {
tech.setSrc(source.src);
};
@@ -424,7 +436,7 @@ Flash.nativeSourceHandler.handleSource = function(source, tech, options){
* Clean up the source handler when disposing the player or switching sources..
* (no cleanup is needed when supporting the format natively)
*/
-Flash.nativeSourceHandler.dispose = function(){};
+Flash.nativeSourceHandler.dispose = function() {};
// Register the native source handler
Flash.registerSourceHandler(Flash.nativeSourceHandler);
@@ -436,7 +448,7 @@ Flash.formats = {
'video/m4v': 'MP4'
};
-Flash.onReady = function(currSwf){
+Flash.onReady = function(currSwf) {
let el = Dom.getEl(currSwf);
let tech = el && el.tech;
@@ -450,7 +462,7 @@ Flash.onReady = function(currSwf){
// The SWF isn't always ready when it says it is. Sometimes the API functions still need to be added to the object.
// If it's not ready, we set a timeout to check again shortly.
-Flash.checkReady = function(tech){
+Flash.checkReady = function(tech) {
// stop worrying if the tech has been disposed
if (!tech.el()) {
return;
@@ -462,20 +474,21 @@ Flash.checkReady = function(tech){
tech.triggerReady();
} else {
// wait longer
- this.setTimeout(function(){
- Flash['checkReady'](tech);
+ this.setTimeout(function() {
+ Flash.checkReady(tech);
}, 50);
}
};
// Trigger events from the swf on the player
-Flash.onEvent = function(swfID, eventName){
+Flash.onEvent = function(swfID, eventName) {
let tech = Dom.getEl(swfID).tech;
+
tech.trigger(eventName, Array.prototype.slice.call(arguments, 2));
};
// Log errors from the swf
-Flash.onError = function(swfID, err){
+Flash.onError = function(swfID, err) {
const tech = Dom.getEl(swfID).tech;
// trigger MEDIA_ERR_SRC_NOT_SUPPORTED
@@ -488,7 +501,7 @@ Flash.onError = function(swfID, err){
};
// Flash Version Check
-Flash.version = function(){
+Flash.version = function() {
let version = '0,0,0';
// IE
@@ -496,18 +509,20 @@ Flash.version = function(){
version = new window.ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version').replace(/\D+/g, ',').match(/^,?(.+),?$/)[1];
// other browsers
- } catch(e) {
+ } catch (e) {
try {
- if (navigator.mimeTypes['application/x-shockwave-flash'].enabledPlugin){
+ if (navigator.mimeTypes['application/x-shockwave-flash'].enabledPlugin) {
version = (navigator.plugins['Shockwave Flash 2.0'] || navigator.plugins['Shockwave Flash']).description.replace(/\D+/g, ',').match(/^,?(.+),?$/)[1];
}
- } catch(err) {}
+ } catch (err) {
+ // satisfy linter
+ }
}
return version.split(',');
};
// Flash embedding method. Only used in non-iframe mode
-Flash.embed = function(swf, flashVars, params, attributes){
+Flash.embed = function(swf, flashVars, params, attributes) {
const code = Flash.getEmbedCode(swf, flashVars, params, attributes);
// Get element by embedding code and retrieving created element
@@ -516,7 +531,7 @@ Flash.embed = function(swf, flashVars, params, attributes){
return obj;
};
-Flash.getEmbedCode = function(swf, flashVars, params, attributes){
+Flash.getEmbedCode = function(swf, flashVars, params, attributes) {
const objTag = '`;
});
attributes = assign({
// Add swf to attributes (need both for IE and Others to work)
- 'data': swf,
+ data: swf,
// Default to 100% width/height
- 'width': '100%',
- 'height': '100%'
+ width: '100%',
+ height: '100%'
}, attributes);
// Create Attributes string
- Object.getOwnPropertyNames(attributes).forEach(function(key){
+ Object.getOwnPropertyNames(attributes).forEach(function(key) {
attrsString += `${key}="${attributes[key]}" `;
});
diff --git a/src/js/tech/html5.js b/src/js/tech/html5.js
index 8d72e042c9..6b5f1e1420 100644
--- a/src/js/tech/html5.js
+++ b/src/js/tech/html5.js
@@ -10,7 +10,6 @@ import * as Url from '../utils/url.js';
import * as Fn from '../utils/fn.js';
import log from '../utils/log.js';
import tsml from 'tsml';
-import TextTrack from '../../../src/js/tracks/text-track.js';
import * as browser from '../utils/browser.js';
import document from 'global/document';
import window from 'global/window';
@@ -28,7 +27,7 @@ import toTitleCase from '../utils/to-title-case.js';
*/
class Html5 extends Tech {
- constructor(options, ready){
+ constructor(options, ready) {
super(options, ready);
const source = options.source;
@@ -74,7 +73,7 @@ class Html5 extends Tech {
}
}
- for (let i=0; i= 0; i--) {
const attr = settingsAttrs[i];
let overwriteAttrs = {};
+
if (typeof this.options_[attr] !== 'undefined') {
overwriteAttrs[attr] = this.options_[attr];
}
@@ -232,6 +235,7 @@ class Html5 extends Tech {
let setLoadstartFired = function() {
loadstartFired = true;
};
+
this.on('loadstart', setLoadstartFired);
let triggerLoadstart = function() {
@@ -241,9 +245,10 @@ class Html5 extends Tech {
this.trigger('loadstart');
}
};
+
this.on('loadedmetadata', triggerLoadstart);
- this.ready(function(){
+ this.ready(function() {
this.off('loadstart', setLoadstartFired);
this.off('loadedmetadata', triggerLoadstart);
@@ -281,8 +286,8 @@ class Html5 extends Tech {
}
// We still need to give the player time to add event listeners
- this.ready(function(){
- eventsToTrigger.forEach(function(type){
+ this.ready(function() {
+ eventsToTrigger.forEach(function(type) {
this.trigger(type);
}, this);
});
@@ -303,7 +308,7 @@ class Html5 extends Tech {
tt.addEventListener('addtrack', this.handleTextTrackAdd_);
tt.addEventListener('removetrack', this.handleTextTrackRemove_);
}
-
+
// Remove (native) texttracks that are not used anymore
this.on('loadstart', this.removeOldTextTracks_);
}
@@ -311,6 +316,7 @@ class Html5 extends Tech {
handleTextTrackChange(e) {
let tt = this.textTracks();
+
this.textTracks().trigger({
type: 'change',
target: tt,
@@ -329,6 +335,7 @@ class Html5 extends Tech {
handleVideoTrackChange_(e) {
let vt = this.videoTracks();
+
this.videoTracks().trigger({
type: 'change',
target: vt,
@@ -347,6 +354,7 @@ class Html5 extends Tech {
handleAudioTrackChange_(e) {
let audioTrackList = this.audioTracks();
+
this.audioTracks().trigger({
type: 'change',
target: audioTrackList,
@@ -374,14 +382,15 @@ class Html5 extends Tech {
// This will loop over the techTracks and check if they are still used by the HTML5 video element
// If not, they will be removed from the emulated list
let removeTracks = [];
+
if (!elTracks) {
return;
}
for (let i = 0; i < techTracks.length; i++) {
let techTrack = techTracks[i];
-
let found = false;
+
for (let j = 0; j < elTracks.length; j++) {
if (elTracks[j] === techTrack) {
found = true;
@@ -396,6 +405,7 @@ class Html5 extends Tech {
for (let i = 0; i < removeTracks.length; i++) {
const track = removeTracks[i];
+
techTracks.removeTrack_(track);
}
}
@@ -403,18 +413,21 @@ class Html5 extends Tech {
removeOldTextTracks_() {
const techTracks = this.textTracks();
const elTracks = this.el().textTracks;
+
this.removeOldTracks_(techTracks, elTracks);
}
removeOldAudioTracks_() {
const techTracks = this.audioTracks();
const elTracks = this.el().audioTracks;
+
this.removeOldTracks_(techTracks, elTracks);
}
removeOldVideoTracks_() {
const techTracks = this.videoTracks();
const elTracks = this.el().videoTracks;
+
this.removeOldTracks_(techTracks, elTracks);
}
@@ -423,14 +436,18 @@ class Html5 extends Tech {
*
* @method play
*/
- play() { this.el_.play(); }
+ play() {
+ this.el_.play();
+ }
/**
* Pause for html5 tech
*
* @method pause
*/
- pause() { this.el_.pause(); }
+ pause() {
+ this.el_.pause();
+ }
/**
* Paused for html5 tech
@@ -438,7 +455,9 @@ class Html5 extends Tech {
* @return {Boolean}
* @method paused
*/
- paused() { return this.el_.paused; }
+ paused() {
+ return this.el_.paused;
+ }
/**
* Get current time
@@ -446,7 +465,9 @@ class Html5 extends Tech {
* @return {Number}
* @method currentTime
*/
- currentTime() { return this.el_.currentTime; }
+ currentTime() {
+ return this.el_.currentTime;
+ }
/**
* Set current time
@@ -457,7 +478,7 @@ class Html5 extends Tech {
setCurrentTime(seconds) {
try {
this.el_.currentTime = seconds;
- } catch(e) {
+ } catch (e) {
log(e, 'Video is not ready. (Video.js)');
// this.warning(VideoJS.warnings.videoNotReady);
}
@@ -469,7 +490,9 @@ class Html5 extends Tech {
* @return {Number}
* @method duration
*/
- duration() { return this.el_.duration || 0; }
+ duration() {
+ return this.el_.duration || 0;
+ }
/**
* Get a TimeRange object that represents the intersection
@@ -479,7 +502,9 @@ class Html5 extends Tech {
* @return {TimeRangeObject}
* @method buffered
*/
- buffered() { return this.el_.buffered; }
+ buffered() {
+ return this.el_.buffered;
+ }
/**
* Get volume level
@@ -487,7 +512,9 @@ class Html5 extends Tech {
* @return {Number}
* @method volume
*/
- volume() { return this.el_.volume; }
+ volume() {
+ return this.el_.volume;
+ }
/**
* Set volume level
@@ -495,7 +522,9 @@ class Html5 extends Tech {
* @param {Number} percentAsDecimal Volume percent as a decimal
* @method setVolume
*/
- setVolume(percentAsDecimal) { this.el_.volume = percentAsDecimal; }
+ setVolume(percentAsDecimal) {
+ this.el_.volume = percentAsDecimal;
+ }
/**
* Get if muted
@@ -503,7 +532,9 @@ class Html5 extends Tech {
* @return {Boolean}
* @method muted
*/
- muted() { return this.el_.muted; }
+ muted() {
+ return this.el_.muted;
+ }
/**
* Set muted
@@ -511,7 +542,9 @@ class Html5 extends Tech {
* @param {Boolean} If player is to be muted or note
* @method setMuted
*/
- setMuted(muted) { this.el_.muted = muted; }
+ setMuted(muted) {
+ this.el_.muted = muted;
+ }
/**
* Get player width
@@ -519,7 +552,9 @@ class Html5 extends Tech {
* @return {Number}
* @method width
*/
- width() { return this.el_.offsetWidth; }
+ width() {
+ return this.el_.offsetWidth;
+ }
/**
* Get player height
@@ -527,7 +562,9 @@ class Html5 extends Tech {
* @return {Number}
* @method height
*/
- height() { return this.el_.offsetHeight; }
+ height() {
+ return this.el_.offsetHeight;
+ }
/**
* Get if there is fullscreen support
@@ -538,8 +575,9 @@ class Html5 extends Tech {
supportsFullScreen() {
if (typeof this.el_.webkitEnterFullScreen === 'function') {
let userAgent = window.navigator.userAgent;
+
// Seems to be broken in Chromium/Chrome && Safari in Leopard
- if (/Android/.test(userAgent) || !/Chrome|Mac OS X 10.5/.test(userAgent)) {
+ if ((/Android/).test(userAgent) || !(/Chrome|Mac OS X 10.5/).test(userAgent)) {
return true;
}
}
@@ -552,7 +590,7 @@ class Html5 extends Tech {
* @method enterFullScreen
*/
enterFullScreen() {
- var video = this.el_;
+ let video = this.el_;
if ('webkitDisplayingFullscreen' in video) {
this.one('webkitbeginfullscreen', function() {
@@ -571,7 +609,7 @@ class Html5 extends Tech {
// playing and pausing synchronously during the transition to fullscreen
// can get iOS ~6.1 devices into a play/pause loop
- this.setTimeout(function(){
+ this.setTimeout(function() {
video.pause();
video.webkitEnterFullScreen();
}, 0);
@@ -599,10 +637,10 @@ class Html5 extends Tech {
src(src) {
if (src === undefined) {
return this.el_.src;
- } else {
- // Setting src through `src` instead of `setSrc` will be deprecated
- this.setSrc(src);
}
+
+ // Setting src through `src` instead of `setSrc` will be deprecated
+ this.setSrc(src);
}
/**
@@ -621,7 +659,7 @@ class Html5 extends Tech {
*
* @method load
*/
- load(){
+ load() {
this.el_.load();
}
@@ -643,9 +681,8 @@ class Html5 extends Tech {
currentSrc() {
if (this.currentSource_) {
return this.currentSource_.src;
- } else {
- return this.el_.currentSrc;
}
+ return this.el_.currentSrc;
}
/**
@@ -654,7 +691,9 @@ class Html5 extends Tech {
* @return {String}
* @method poster
*/
- poster() { return this.el_.poster; }
+ poster() {
+ return this.el_.poster;
+ }
/**
* Set poster
@@ -662,7 +701,9 @@ class Html5 extends Tech {
* @param {String} val URL to poster image
* @method
*/
- setPoster(val) { this.el_.poster = val; }
+ setPoster(val) {
+ this.el_.poster = val;
+ }
/**
* Get preload attribute
@@ -670,7 +711,9 @@ class Html5 extends Tech {
* @return {String}
* @method preload
*/
- preload() { return this.el_.preload; }
+ preload() {
+ return this.el_.preload;
+ }
/**
* Set preload attribute
@@ -678,7 +721,9 @@ class Html5 extends Tech {
* @param {String} val Value for preload attribute
* @method setPreload
*/
- setPreload(val) { this.el_.preload = val; }
+ setPreload(val) {
+ this.el_.preload = val;
+ }
/**
* Get autoplay attribute
@@ -686,7 +731,9 @@ class Html5 extends Tech {
* @return {String}
* @method autoplay
*/
- autoplay() { return this.el_.autoplay; }
+ autoplay() {
+ return this.el_.autoplay;
+ }
/**
* Set autoplay attribute
@@ -694,7 +741,9 @@ class Html5 extends Tech {
* @param {String} val Value for preload attribute
* @method setAutoplay
*/
- setAutoplay(val) { this.el_.autoplay = val; }
+ setAutoplay(val) {
+ this.el_.autoplay = val;
+ }
/**
* Get controls attribute
@@ -702,7 +751,9 @@ class Html5 extends Tech {
* @return {String}
* @method controls
*/
- controls() { return this.el_.controls; }
+ controls() {
+ return this.el_.controls;
+ }
/**
* Set controls attribute
@@ -710,7 +761,9 @@ class Html5 extends Tech {
* @param {String} val Value for controls attribute
* @method setControls
*/
- setControls(val) { this.el_.controls = !!val; }
+ setControls(val) {
+ this.el_.controls = !!val;
+ }
/**
* Get loop attribute
@@ -718,7 +771,9 @@ class Html5 extends Tech {
* @return {String}
* @method loop
*/
- loop() { return this.el_.loop; }
+ loop() {
+ return this.el_.loop;
+ }
/**
* Set loop attribute
@@ -726,7 +781,9 @@ class Html5 extends Tech {
* @param {String} val Value for loop attribute
* @method setLoop
*/
- setLoop(val) { this.el_.loop = val; }
+ setLoop(val) {
+ this.el_.loop = val;
+ }
/**
* Get error value
@@ -734,7 +791,9 @@ class Html5 extends Tech {
* @return {String}
* @method error
*/
- error() { return this.el_.error; }
+ error() {
+ return this.el_.error;
+ }
/**
* Get whether or not the player is in the "seeking" state
@@ -742,7 +801,9 @@ class Html5 extends Tech {
* @return {Boolean}
* @method seeking
*/
- seeking() { return this.el_.seeking; }
+ seeking() {
+ return this.el_.seeking;
+ }
/**
* Get a TimeRanges object that represents the
@@ -752,7 +813,9 @@ class Html5 extends Tech {
* @return {TimeRangeObject}
* @method seekable
*/
- seekable() { return this.el_.seekable; }
+ seekable() {
+ return this.el_.seekable;
+ }
/**
* Get if video ended
@@ -760,7 +823,9 @@ class Html5 extends Tech {
* @return {Boolean}
* @method ended
*/
- ended() { return this.el_.ended; }
+ ended() {
+ return this.el_.ended;
+ }
/**
* Get the value of the muted content attribute
@@ -770,7 +835,9 @@ class Html5 extends Tech {
* @return {Boolean}
* @method defaultMuted
*/
- defaultMuted() { return this.el_.defaultMuted; }
+ defaultMuted() {
+ return this.el_.defaultMuted;
+ }
/**
* Get desired speed at which the media resource is to play
@@ -778,7 +845,9 @@ class Html5 extends Tech {
* @return {Number}
* @method playbackRate
*/
- playbackRate() { return this.el_.playbackRate; }
+ playbackRate() {
+ return this.el_.playbackRate;
+ }
/**
* Returns a TimeRanges object that represents the ranges of the
@@ -787,7 +856,9 @@ class Html5 extends Tech {
* timeline that has been reached through normal playback
* @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-media-played
*/
- played() { return this.el_.played; }
+ played() {
+ return this.el_.played;
+ }
/**
* Set desired speed at which the media resource is to play
@@ -795,7 +866,9 @@ class Html5 extends Tech {
* @param {Number} val Speed at which the media resource is to play
* @method setPlaybackRate
*/
- setPlaybackRate(val) { this.el_.playbackRate = val; }
+ setPlaybackRate(val) {
+ this.el_.playbackRate = val;
+ }
/**
* Get the current state of network activity for the element, from
@@ -808,7 +881,9 @@ class Html5 extends Tech {
* @return {Number}
* @method networkState
*/
- networkState() { return this.el_.networkState; }
+ networkState() {
+ return this.el_.networkState;
+ }
/**
* Get a value that expresses the current state of the element
@@ -823,7 +898,9 @@ class Html5 extends Tech {
* @return {Number}
* @method readyState
*/
- readyState() { return this.el_.readyState; }
+ readyState() {
+ return this.el_.readyState;
+ }
/**
* Get width of video
@@ -831,7 +908,9 @@ class Html5 extends Tech {
* @return {Number}
* @method videoWidth
*/
- videoWidth() { return this.el_.videoWidth; }
+ videoWidth() {
+ return this.el_.videoWidth;
+ }
/**
* Get height of video
@@ -839,7 +918,9 @@ class Html5 extends Tech {
* @return {Number}
* @method videoHeight
*/
- videoHeight() { return this.el_.videoHeight; }
+ videoHeight() {
+ return this.el_.videoHeight;
+ }
/**
* Get text tracks
@@ -862,7 +943,7 @@ class Html5 extends Tech {
* @method addTextTrack
*/
addTextTrack(kind, label, language) {
- if (!this['featuresNativeTextTracks']) {
+ if (!this.featuresNativeTextTracks) {
return super.addTextTrack(kind, label, language);
}
@@ -877,8 +958,8 @@ class Html5 extends Tech {
* @return {HTMLTrackElement}
* @method addRemoteTextTrack
*/
- addRemoteTextTrack(options={}) {
- if (!this['featuresNativeTextTracks']) {
+ addRemoteTextTrack(options = {}) {
+ if (!this.featuresNativeTextTracks) {
return super.addRemoteTextTrack(options);
}
@@ -919,12 +1000,11 @@ class Html5 extends Tech {
* @method removeRemoteTextTrack
*/
removeRemoteTextTrack(track) {
- if (!this['featuresNativeTextTracks']) {
+ if (!this.featuresNativeTextTracks) {
return super.removeRemoteTextTrack(track);
}
- let tracks, i;
-
+ let tracks;
let trackElement = this.remoteTextTrackEls().getTrackElementByTrack_(track);
// remove HTMLTrackElement and TextTrack from remote list
@@ -933,7 +1013,8 @@ class Html5 extends Tech {
tracks = this.$$('track');
- i = tracks.length;
+ let i = tracks.length;
+
while (i--) {
if (track === tracks[i] || track === tracks[i].track) {
this.el().removeChild(tracks[i]);
@@ -943,7 +1024,6 @@ class Html5 extends Tech {
}
-
/* HTML5 Support Testing ---------------------------------------------------- */
/*
@@ -955,6 +1035,7 @@ class Html5 extends Tech {
*/
Html5.TEST_VID = document.createElement('video');
let track = document.createElement('track');
+
track.kind = 'captions';
track.srclang = 'en';
track.label = 'English';
@@ -965,10 +1046,10 @@ Html5.TEST_VID.appendChild(track);
*
* @return {Boolean}
*/
-Html5.isSupported = function(){
+Html5.isSupported = function() {
// IE9 with no Media Player is a LIAR! (#984)
try {
- Html5.TEST_VID['volume'] = 0.5;
+ Html5.TEST_VID.volume = 0.5;
} catch (e) {
return false;
}
@@ -994,12 +1075,12 @@ Html5.nativeSourceHandler = {};
* @param {String} type The mimetype to check
* @return {String} 'probably', 'maybe', or '' (empty string)
*/
-Html5.nativeSourceHandler.canPlayType = function(type){
+Html5.nativeSourceHandler.canPlayType = function(type) {
// IE9 on Windows 7 without MediaPlayer throws an error here
// https://github.com/videojs/video.js/issues/519
try {
return Html5.TEST_VID.canPlayType(type);
- } catch(e) {
+ } catch (e) {
return '';
}
};
@@ -1011,15 +1092,15 @@ Html5.nativeSourceHandler.canPlayType = function(type){
* @param {Object} options The options passed to the tech
* @return {String} 'probably', 'maybe', or '' (empty string)
*/
-Html5.nativeSourceHandler.canHandleSource = function(source, options){
- var match, ext;
+Html5.nativeSourceHandler.canHandleSource = function(source, options) {
// If a type was provided we should rely on that
if (source.type) {
return Html5.nativeSourceHandler.canPlayType(source.type);
+
+ // If no type, fall back to checking 'video/[EXTENSION]'
} else if (source.src) {
- // If no type, fall back to checking 'video/[EXTENSION]'
- ext = Url.getFileExtension(source.src);
+ let ext = Url.getFileExtension(source.src);
return Html5.nativeSourceHandler.canPlayType(`video/${ext}`);
}
@@ -1036,7 +1117,7 @@ Html5.nativeSourceHandler.canHandleSource = function(source, options){
* @param {Html5} tech The instance of the Html5 tech
* @param {Object} options The options to pass to the source
*/
-Html5.nativeSourceHandler.handleSource = function(source, tech, options){
+Html5.nativeSourceHandler.handleSource = function(source, tech, options) {
tech.setSrc(source.src);
};
@@ -1044,7 +1125,7 @@ Html5.nativeSourceHandler.handleSource = function(source, tech, options){
* 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(){};
+Html5.nativeSourceHandler.dispose = function() {};
// Register the native source handler
Html5.registerSourceHandler(Html5.nativeSourceHandler);
@@ -1056,13 +1137,14 @@ Html5.registerSourceHandler(Html5.nativeSourceHandler);
*
* @return {Boolean}
*/
-Html5.canControlVolume = function(){
+Html5.canControlVolume = function() {
// IE will error if Windows Media Player not installed #3315
try {
- var volume = Html5.TEST_VID.volume;
+ let volume = Html5.TEST_VID.volume;
+
Html5.TEST_VID.volume = (volume / 2) + 0.1;
return volume !== Html5.TEST_VID.volume;
- } catch(e) {
+ } catch (e) {
return false;
}
};
@@ -1072,7 +1154,7 @@ Html5.canControlVolume = function(){
*
* @return {Boolean}
*/
-Html5.canControlPlaybackRate = function(){
+Html5.canControlPlaybackRate = function() {
// Playback rate API is implemented in Android Chrome, but doesn't do anything
// https://github.com/videojs/video.js/issues/3180
if (browser.IS_ANDROID && browser.IS_CHROME) {
@@ -1080,10 +1162,11 @@ Html5.canControlPlaybackRate = function(){
}
// IE will error if Windows Media Player not installed #3315
try {
- var playbackRate = Html5.TEST_VID.playbackRate;
+ let playbackRate = Html5.TEST_VID.playbackRate;
+
Html5.TEST_VID.playbackRate = (playbackRate / 2) + 0.1;
return playbackRate !== Html5.TEST_VID.playbackRate;
- } catch(e) {
+ } catch (e) {
return false;
}
};
@@ -1094,7 +1177,7 @@ Html5.canControlPlaybackRate = function(){
* @return {Boolean}
*/
Html5.supportsNativeTextTracks = function() {
- var supportsTextTracks;
+ let supportsTextTracks;
// Figure out native text track support
// If mode is a number, we cannot change it because it'll disappear from view.
@@ -1103,7 +1186,7 @@ Html5.supportsNativeTextTracks = function() {
// TODO: Investigate firefox: https://github.com/videojs/video.js/issues/1862
supportsTextTracks = !!Html5.TEST_VID.textTracks;
if (supportsTextTracks && Html5.TEST_VID.textTracks.length > 0) {
- supportsTextTracks = typeof Html5.TEST_VID.textTracks[0]['mode'] !== 'number';
+ supportsTextTracks = typeof Html5.TEST_VID.textTracks[0].mode !== 'number';
}
if (supportsTextTracks && browser.IS_FIREFOX) {
supportsTextTracks = false;
@@ -1122,6 +1205,7 @@ Html5.supportsNativeTextTracks = function() {
*/
Html5.supportsNativeVideoTracks = function() {
let supportsVideoTracks = !!Html5.TEST_VID.videoTracks;
+
return supportsVideoTracks;
};
@@ -1132,10 +1216,10 @@ Html5.supportsNativeVideoTracks = function() {
*/
Html5.supportsNativeAudioTracks = function() {
let supportsAudioTracks = !!Html5.TEST_VID.audioTracks;
+
return supportsAudioTracks;
};
-
/**
* An array of events available on the Html5 tech.
*
@@ -1172,14 +1256,14 @@ Html5.Events = [
*
* @type {Boolean}
*/
-Html5.prototype['featuresVolumeControl'] = Html5.canControlVolume();
+Html5.prototype.featuresVolumeControl = Html5.canControlVolume();
/*
* Set the tech's playbackRate support status
*
* @type {Boolean}
*/
-Html5.prototype['featuresPlaybackRate'] = Html5.canControlPlaybackRate();
+Html5.prototype.featuresPlaybackRate = Html5.canControlPlaybackRate();
/*
* Set the tech's status on moving the video element.
@@ -1187,41 +1271,41 @@ Html5.prototype['featuresPlaybackRate'] = Html5.canControlPlaybackRate();
*
* @type {Boolean}
*/
-Html5.prototype['movingMediaElementInDOM'] = !browser.IS_IOS;
+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;
+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;
+Html5.prototype.featuresProgressEvents = true;
/*
* Sets the tech's status on native text track support
*
* @type {Boolean}
*/
-Html5.prototype['featuresNativeTextTracks'] = Html5.supportsNativeTextTracks();
+Html5.prototype.featuresNativeTextTracks = Html5.supportsNativeTextTracks();
/**
* Sets the tech's status on native text track support
*
* @type {Boolean}
*/
-Html5.prototype['featuresNativeVideoTracks'] = Html5.supportsNativeVideoTracks();
+Html5.prototype.featuresNativeVideoTracks = Html5.supportsNativeVideoTracks();
/**
* Sets the tech's status on native audio track support
*
* @type {Boolean}
*/
-Html5.prototype['featuresNativeAudioTracks'] = Html5.supportsNativeAudioTracks();
+Html5.prototype.featuresNativeAudioTracks = Html5.supportsNativeAudioTracks();
// HTML5 Feature detection and Device Fixes --------------------------------- //
let canPlayType;
@@ -1249,7 +1333,7 @@ Html5.patchCanPlayType = function() {
canPlayType = Html5.TEST_VID.constructor.prototype.canPlayType;
}
- Html5.TEST_VID.constructor.prototype.canPlayType = function(type){
+ Html5.TEST_VID.constructor.prototype.canPlayType = function(type) {
if (type && mp4RE.test(type)) {
return 'maybe';
}
@@ -1259,7 +1343,8 @@ Html5.patchCanPlayType = function() {
};
Html5.unpatchCanPlayType = function() {
- var r = Html5.TEST_VID.constructor.prototype.canPlayType;
+ let r = Html5.TEST_VID.constructor.prototype.canPlayType;
+
Html5.TEST_VID.constructor.prototype.canPlayType = canPlayType;
canPlayType = null;
return r;
@@ -1268,15 +1353,17 @@ Html5.unpatchCanPlayType = function() {
// by default, patch the video element
Html5.patchCanPlayType();
-Html5.disposeMediaElement = function(el){
- if (!el) { return; }
+Html5.disposeMediaElement = function(el) {
+ if (!el) {
+ return;
+ }
if (el.parentNode) {
el.parentNode.removeChild(el);
}
// remove any child track or source nodes to prevent their loading
- while(el.hasChildNodes()) {
+ while (el.hasChildNodes()) {
el.removeChild(el.firstChild);
}
@@ -1294,15 +1381,18 @@ Html5.disposeMediaElement = function(el){
} catch (e) {
// not supported
}
- })();
+ }());
}
};
-Html5.resetMediaElement = function(el){
- if (!el) { return; }
+Html5.resetMediaElement = function(el) {
+ if (!el) {
+ return;
+ }
let sources = el.querySelectorAll('source');
let i = sources.length;
+
while (i--) {
el.removeChild(sources[i]);
}
@@ -1316,8 +1406,10 @@ Html5.resetMediaElement = function(el){
(function() {
try {
el.load();
- } catch (e) {}
- })();
+ } catch (e) {
+ // satisfy linter
+ }
+ }());
}
};
diff --git a/src/js/tech/loader.js b/src/js/tech/loader.js
index 14bc28c184..5d303e0eef 100644
--- a/src/js/tech/loader.js
+++ b/src/js/tech/loader.js
@@ -3,7 +3,6 @@
*/
import Component from '../component.js';
import Tech from './tech.js';
-import window from 'global/window';
import toTitleCase from '../utils/to-title-case.js';
/**
@@ -18,16 +17,17 @@ import toTitleCase from '../utils/to-title-case.js';
*/
class MediaLoader extends Component {
- constructor(player, options, ready){
+ constructor(player, options, ready) {
super(player, options, ready);
// If there are no sources when the player is initialized,
// load the first supported playback technology.
- if (!options.playerOptions['sources'] || options.playerOptions['sources'].length === 0) {
- for (let i=0, j=options.playerOptions['techOrder']; i {
let list = this[`${type}Tracks`]() || [];
let i = list.length;
+
while (i--) {
let track = list[i];
+
if (type === 'text') {
this.removeRemoteTextTrack(track);
}
@@ -315,7 +342,9 @@ class Tech extends Component {
*/
setCurrentTime() {
// improve the accuracy of manual timeupdates
- if (this.manualTimeUpdates) { this.trigger({ type: 'timeupdate', target: this, manuallyTriggered: true }); }
+ if (this.manualTimeUpdates) {
+ this.trigger({ type: 'timeupdate', target: this, manuallyTriggered: true });
+ }
}
/**
@@ -330,7 +359,9 @@ class Tech extends Component {
let tracks = this.textTracks();
- if (!tracks) return;
+ if (!tracks) {
+ return;
+ }
tracks.addEventListener('removetrack', textTrackListChanges);
tracks.addEventListener('addtrack', textTrackListChanges);
@@ -341,7 +372,6 @@ class Tech extends Component {
}));
}
-
/**
* Initialize audio and video track listeners
*
@@ -374,12 +404,14 @@ class Tech extends Component {
*/
emulateTextTracks() {
let tracks = this.textTracks();
+
if (!tracks) {
return;
}
- if (!window['WebVTT'] && this.el().parentNode != null) {
+ if (!window.WebVTT && this.el().parentNode != null) {
let script = document.createElement('script');
+
script.src = this.options_['vtt.js'] || '../node_modules/videojs-vtt.js/dist/vtt.js';
script.onload = () => {
this.trigger('vttjsloaded');
@@ -393,7 +425,7 @@ class Tech extends Component {
});
// but have not loaded yet and we set it to true before the inject so that
// we don't overwrite the injected window.WebVTT if it loads right away
- window['WebVTT'] = true;
+ window.WebVTT = true;
this.el().parentNode.appendChild(script);
}
@@ -403,6 +435,7 @@ class Tech extends Component {
for (let i = 0; i < tracks.length; i++) {
let track = tracks[i];
+
track.removeEventListener('cuechange', updateDisplay);
if (track.mode === 'showing') {
track.addEventListener('cuechange', updateDisplay);
@@ -620,7 +653,7 @@ class Tech extends Component {
* @type {TextTrackList}
* @private
*/
-Tech.prototype.textTracks_;
+Tech.prototype.textTracks_; // eslint-disable-line
/**
* List of associated audio tracks
@@ -628,7 +661,7 @@ Tech.prototype.textTracks_;
* @type {AudioTrackList}
* @private
*/
-Tech.prototype.audioTracks_;
+Tech.prototype.audioTracks_; // eslint-disable-line
/**
* List of associated video tracks
@@ -636,27 +669,7 @@ Tech.prototype.audioTracks_;
* @type {VideoTrackList}
* @private
*/
-Tech.prototype.videoTracks_;
-
-
-var createTrackHelper = function(self, kind, label, language, options={}) {
- let tracks = self.textTracks();
-
- options.kind = kind;
-
- if (label) {
- options.label = label;
- }
- if (language) {
- options.language = language;
- }
- options.tech = self;
-
- let track = new TextTrack(options);
- tracks.addTrack_(track);
-
- return track;
-};
+Tech.prototype.videoTracks_; // eslint-disable-line
Tech.prototype.featuresVolumeControl = true;
@@ -671,7 +684,7 @@ Tech.prototype.featuresTimeupdateEvents = false;
Tech.prototype.featuresNativeTextTracks = false;
-/*
+/**
* A functional mixin for techs that want to use the Source Handler pattern.
*
* ##### EXAMPLE:
@@ -679,16 +692,17 @@ Tech.prototype.featuresNativeTextTracks = false;
* Tech.withSourceHandlers.call(MyTech);
*
*/
-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
- */
- _Tech.registerSourceHandler = function(handler, index){
+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
+ */
+ _Tech.registerSourceHandler = function(handler, index) {
let handlers = _Tech.sourceHandlers;
if (!handlers) {
@@ -703,12 +717,12 @@ Tech.withSourceHandlers = function(_Tech){
handlers.splice(index, 0, handler);
};
- /*
+ /**
* Check if the tech can support the given type
* @param {String} type The mimetype to check
* @return {String} 'probably', 'maybe', or '' (empty string)
*/
- _Tech.canPlayType = function(type){
+ _Tech.canPlayType = function(type) {
let handlers = _Tech.sourceHandlers || [];
let can;
@@ -723,15 +737,15 @@ Tech.withSourceHandlers = function(_Tech){
return '';
};
- /*
- * Return the first source handler that supports the source
- * TODO: Answer question: should 'probably' be prioritized over 'maybe'
- * @param {Object} source The source object
- * @param {Object} options The options passed to the tech
- * @returns {Object} The first source handler that supports the source
- * @returns {null} Null if no source handler is found
- */
- _Tech.selectSourceHandler = function(source, options){
+ /**
+ * Return the first source handler that supports the source
+ * TODO: Answer question: should 'probably' be prioritized over 'maybe'
+ * @param {Object} source The source object
+ * @param {Object} options The options passed to the tech
+ * @returns {Object} The first source handler that supports the source
+ * @returns {null} Null if no source handler is found
+ */
+ _Tech.selectSourceHandler = function(source, options) {
let handlers = _Tech.sourceHandlers || [];
let can;
@@ -746,13 +760,13 @@ Tech.withSourceHandlers = function(_Tech){
return null;
};
- /*
+ /**
* Check if the tech can support the given source
* @param {Object} srcObj The source object
* @param {Object} options The options passed to the tech
* @return {String} 'probably', 'maybe', or '' (empty string)
*/
- _Tech.canPlaySource = function(srcObj, options){
+ _Tech.canPlaySource = function(srcObj, options) {
let sh = _Tech.selectSourceHandler(srcObj, options);
if (sh) {
@@ -762,16 +776,16 @@ Tech.withSourceHandlers = function(_Tech){
return '';
};
- /*
+ /**
* When using a source handler, prefer its implementation of
* any function normally provided by the tech.
*/
let deferrable = [
- 'seekable',
- 'duration'
- ];
+ 'seekable',
+ 'duration'
+ ];
- deferrable.forEach(function (fnName) {
+ deferrable.forEach(function(fnName) {
let originalFn = this[fnName];
if (typeof originalFn !== 'function') {
@@ -786,14 +800,14 @@ Tech.withSourceHandlers = function(_Tech){
};
}, _Tech.prototype);
- /*
- * Create a function for setting the source using a source object
- * and source handlers.
- * Should never be called unless a source handler was found.
- * @param {Object} source A source object with src and type keys
- * @return {Tech} self
- */
- _Tech.prototype.setSource = function(source){
+ /**
+ * 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, this.options_);
if (!sh) {
diff --git a/src/js/tracks/audio-track-list.js b/src/js/tracks/audio-track-list.js
index d1499bec29..216469ba39 100644
--- a/src/js/tracks/audio-track-list.js
+++ b/src/js/tracks/audio-track-list.js
@@ -21,6 +21,7 @@ const disableOthers = function(list, track) {
list[i].enabled = false;
}
};
+
/**
* A list of possible audio tracks. All functionality is in the
* base class Tracklist and the spec for AudioTrackList is located at:
diff --git a/src/js/tracks/audio-track.js b/src/js/tracks/audio-track.js
index e5f0f7854a..c5f1afacb4 100644
--- a/src/js/tracks/audio-track.js
+++ b/src/js/tracks/audio-track.js
@@ -37,7 +37,9 @@ class AudioTrack extends Track {
}
Object.defineProperty(track, 'enabled', {
- get() { return enabled; },
+ get() {
+ return enabled;
+ },
set(newEnabled) {
// an invalid or unchanged value
if (typeof newEnabled !== 'boolean' || newEnabled === enabled) {
diff --git a/src/js/tracks/html-track-element-list.js b/src/js/tracks/html-track-element-list.js
index 9b38d05820..300b446a6a 100644
--- a/src/js/tracks/html-track-element-list.js
+++ b/src/js/tracks/html-track-element-list.js
@@ -7,7 +7,7 @@ import document from 'global/document';
class HtmlTrackElementList {
constructor(trackElements = []) {
- let list = this;
+ let list = this; // eslint-disable-line
if (browser.IS_IE8) {
list = document.createElement('custom');
diff --git a/src/js/tracks/html-track-element.js b/src/js/tracks/html-track-element.js
index d799375efb..182b56d76c 100644
--- a/src/js/tracks/html-track-element.js
+++ b/src/js/tracks/html-track-element.js
@@ -39,8 +39,8 @@ class HTMLTrackElement extends EventTarget {
constructor(options = {}) {
super();
- let readyState,
- trackElement = this;
+ let readyState;
+ let trackElement = this; // eslint-disable-line
if (browser.IS_IE8) {
trackElement = document.createElement('custom');
diff --git a/src/js/tracks/text-track-cue-list.js b/src/js/tracks/text-track-cue-list.js
index 3abd7ed069..dd457cad15 100644
--- a/src/js/tracks/text-track-cue-list.js
+++ b/src/js/tracks/text-track-cue-list.js
@@ -20,7 +20,7 @@ import document from 'global/document';
class TextTrackCueList {
constructor(cues) {
- let list = this;
+ let list = this; // eslint-disable-line
if (browser.IS_IE8) {
list = document.createElement('custom');
diff --git a/src/js/tracks/text-track-display.js b/src/js/tracks/text-track-display.js
index 40ca875b37..6cf9402d6d 100644
--- a/src/js/tracks/text-track-display.js
+++ b/src/js/tracks/text-track-display.js
@@ -2,28 +2,60 @@
* @file text-track-display.js
*/
import Component from '../component';
-import Menu from '../menu/menu.js';
-import MenuItem from '../menu/menu-item.js';
-import MenuButton from '../menu/menu-button.js';
import * as Fn from '../utils/fn.js';
-import document from 'global/document';
import window from 'global/window';
const darkGray = '#222';
const lightGray = '#ccc';
const fontMap = {
- monospace: 'monospace',
- sansSerif: 'sans-serif',
- serif: 'serif',
- monospaceSansSerif: '"Andale Mono", "Lucida Console", monospace',
- monospaceSerif: '"Courier New", monospace',
+ monospace: 'monospace',
+ sansSerif: 'sans-serif',
+ serif: 'serif',
+ monospaceSansSerif: '"Andale Mono", "Lucida Console", monospace',
+ monospaceSerif: '"Courier New", monospace',
proportionalSansSerif: 'sans-serif',
- proportionalSerif: 'serif',
- casual: '"Comic Sans MS", Impact, fantasy',
- script: '"Monotype Corsiva", cursive',
- smallcaps: '"Andale Mono", "Lucida Console", monospace, sans-serif'
+ proportionalSerif: 'serif',
+ casual: '"Comic Sans MS", Impact, fantasy',
+ script: '"Monotype Corsiva", cursive',
+ smallcaps: '"Andale Mono", "Lucida Console", monospace, sans-serif'
};
+/**
+ * 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"
+ parseInt(color[1] + color[1], 16) + ',' +
+ parseInt(color[2] + color[2], 16) + ',' +
+ parseInt(color[3] + color[3], 16) + ',' +
+ 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) {
+ try {
+ el.style[style] = rule;
+ } catch (e) {
+
+ // Satisfies linter.
+ return;
+ }
+}
+
/**
* The component for displaying text track cues
*
@@ -35,7 +67,7 @@ const fontMap = {
*/
class TextTrackDisplay extends Component {
- constructor(player, options, ready){
+ constructor(player, options, ready) {
super(player, options, ready);
player.on('loadstart', Fn.bind(this, this.toggleDisplay));
@@ -46,20 +78,20 @@ class TextTrackDisplay extends Component {
// Should probably be moved to an external track loader when we support
// tracks that don't need a display.
player.ready(Fn.bind(this, function() {
- if (player.tech_ && player.tech_['featuresNativeTextTracks']) {
+ if (player.tech_ && player.tech_.featuresNativeTextTracks) {
this.hide();
return;
}
player.on('fullscreenchange', Fn.bind(this, this.updateDisplay));
- let tracks = this.options_.playerOptions['tracks'] || [];
+ let tracks = this.options_.playerOptions.tracks || [];
+
for (let i = 0; i < tracks.length; i++) {
- let track = tracks[i];
- this.player_.addRemoteTextTrack(track);
+ this.player_.addRemoteTextTrack(tracks[i]);
}
- let modes = {'captions': 1, 'subtitles': 1};
+ let modes = {captions: 1, subtitles: 1};
let trackList = this.player_.textTracks();
let firstDesc;
let firstCaptions;
@@ -67,6 +99,7 @@ class TextTrackDisplay extends Component {
if (trackList) {
for (let i = 0; i < trackList.length; i++) {
let track = trackList[i];
+
if (track.default) {
if (track.kind === 'descriptions' && !firstDesc) {
firstDesc = track;
@@ -95,7 +128,7 @@ class TextTrackDisplay extends Component {
* @method toggleDisplay
*/
toggleDisplay() {
- if (this.player_.tech_ && this.player_.tech_['featuresNativeTextTracks']) {
+ if (this.player_.tech_ && this.player_.tech_.featuresNativeTextTracks) {
this.hide();
} else {
this.show();
@@ -123,8 +156,8 @@ class TextTrackDisplay extends Component {
* @method clearDisplay
*/
clearDisplay() {
- if (typeof window['WebVTT'] === 'function') {
- window['WebVTT']['processCues'](window, [], this.el_);
+ if (typeof window.WebVTT === 'function') {
+ window.WebVTT.processCues(window, [], this.el_);
}
}
@@ -134,7 +167,7 @@ class TextTrackDisplay extends Component {
* @method updateDisplay
*/
updateDisplay() {
- var tracks = this.player_.textTracks();
+ let tracks = this.player_.textTracks();
this.clearDisplay();
@@ -150,10 +183,12 @@ class TextTrackDisplay extends Component {
let captionsSubtitlesTrack = null;
let i = tracks.length;
+
while (i--) {
let track = tracks[i];
- if (track['mode'] === 'showing') {
- if (track['kind'] === 'descriptions') {
+
+ if (track.mode === 'showing') {
+ if (track.kind === 'descriptions') {
descriptionsTrack = track;
} else {
captionsSubtitlesTrack = track;
@@ -175,27 +210,30 @@ class TextTrackDisplay extends Component {
* @method updateForTrack
*/
updateForTrack(track) {
- if (typeof window['WebVTT'] !== 'function' || !track['activeCues']) {
+ if (typeof window.WebVTT !== 'function' || !track.activeCues) {
return;
}
- let overrides = this.player_['textTrackSettings'].getValues();
-
+ let overrides = this.player_.textTrackSettings.getValues();
let cues = [];
- for (let i = 0; i < track['activeCues'].length; i++) {
- cues.push(track['activeCues'][i]);
+
+ for (let i = 0; i < track.activeCues.length; i++) {
+ cues.push(track.activeCues[i]);
}
- window['WebVTT']['processCues'](window, cues, this.el_);
+ window.WebVTT.processCues(window, cues, this.el_);
let i = cues.length;
+
while (i--) {
let cue = cues[i];
+
if (!cue) {
continue;
}
let cueDiv = cue.displayState;
+
if (overrides.color) {
cueDiv.firstChild.style.color = overrides.color;
}
@@ -236,6 +274,7 @@ class TextTrackDisplay extends Component {
}
if (overrides.fontPercent && overrides.fontPercent !== 1) {
const fontSize = window.parseFloat(cueDiv.style.fontSize);
+
cueDiv.style.fontSize = (fontSize * overrides.fontPercent) + 'px';
cueDiv.style.height = 'auto';
cueDiv.style.top = 'auto';
@@ -253,38 +292,5 @@ class TextTrackDisplay extends Component {
}
-/**
-* 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"
- parseInt(color[1] + color[1], 16) + ',' +
- parseInt(color[2] + color[2], 16) + ',' +
- parseInt(color[3] + color[3], 16) + ',' +
- 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) {
- //
- try {
- el.style[style] = rule;
- } catch (e) {}
-}
-
Component.registerComponent('TextTrackDisplay', TextTrackDisplay);
export default TextTrackDisplay;
diff --git a/src/js/tracks/text-track-list-converter.js b/src/js/tracks/text-track-list-converter.js
index b7ab4dd1f5..8cc3d69874 100644
--- a/src/js/tracks/text-track-list-converter.js
+++ b/src/js/tracks/text-track-list-converter.js
@@ -13,13 +13,15 @@
* @private
*/
let trackToJson_ = function(track) {
- let ret = ['kind', 'label', 'language', 'id',
- 'inBandMetadataTrackDispatchType',
- 'mode', 'src'].reduce((acc, prop, i) => {
+ let ret = [
+ 'kind', 'label', 'language', 'id',
+ 'inBandMetadataTrackDispatchType', 'mode', 'src'
+ ].reduce((acc, prop, i) => {
+
if (track[prop]) {
acc[prop] = track[prop];
}
-
+
return acc;
}, {
cues: track.cues && Array.prototype.map.call(track.cues, function(cue) {
@@ -50,6 +52,7 @@ let textTracksToJson = function(tech) {
let trackObjs = Array.prototype.map.call(trackEls, (t) => t.track);
let tracks = Array.prototype.map.call(trackEls, function(trackEl) {
let json = trackToJson_(trackEl.track);
+
if (trackEl.src) {
json.src = trackEl.src;
}
@@ -72,6 +75,7 @@ let textTracksToJson = function(tech) {
let jsonToTextTracks = function(json, tech) {
json.forEach(function(track) {
let addedTrack = tech.addRemoteTextTrack(track).track;
+
if (!track.src && track.cues) {
track.cues.forEach((cue) => addedTrack.addCue(cue));
}
diff --git a/src/js/tracks/text-track-settings.js b/src/js/tracks/text-track-settings.js
index 50d845f04b..0baf8c7ff9 100644
--- a/src/js/tracks/text-track-settings.js
+++ b/src/js/tracks/text-track-settings.js
@@ -8,6 +8,159 @@ import log from '../utils/log.js';
import safeParseTuple from 'safe-json-parse/tuple';
import window from 'global/window';
+function captionOptionsMenuTemplate(uniqueId, dialogLabelId, dialogDescriptionId) {
+ let template = `
+
+
Captions Settings Dialog
+
Beginning of dialog window. Escape will cancel and close the window.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `;
+
+ return template;
+}
+
+function getSelectedOptionValue(target) {
+ let selectedOption;
+
+ // not all browsers support selectedOptions, so, fallback to options
+ if (target.selectedOptions) {
+ selectedOption = target.selectedOptions[0];
+ } else if (target.options) {
+ selectedOption = target.options[target.options.selectedIndex];
+ }
+
+ return selectedOption.value;
+}
+
+function setSelectedOption(target, value) {
+ if (!value) {
+ return;
+ }
+
+ let i;
+
+ for (i = 0; i < target.options.length; i++) {
+ const option = target.options[i];
+
+ if (option.value === value) {
+ break;
+ }
+ }
+
+ target.selectedIndex = i;
+}
+
/**
* Manipulate settings of texttracks
*
@@ -76,7 +229,7 @@ class TextTrackSettings extends Component {
innerHTML: captionOptionsMenuTemplate(uniqueId, dialogLabelId, dialogDescriptionId),
tabIndex: -1
}, {
- role: 'dialog',
+ 'role': 'dialog',
'aria-labelledby': dialogLabelId,
'aria-describedby': dialogDescriptionId
});
@@ -106,19 +259,20 @@ class TextTrackSettings extends Component {
const bgOpacity = getSelectedOptionValue(this.$('.vjs-bg-opacity > select'));
const windowColor = getSelectedOptionValue(this.$('.window-color > select'));
const windowOpacity = getSelectedOptionValue(this.$('.vjs-window-opacity > select'));
- const fontPercent = window['parseFloat'](getSelectedOptionValue(this.$('.vjs-font-percent > select')));
+ const fontPercent = window.parseFloat(getSelectedOptionValue(this.$('.vjs-font-percent > select')));
let result = {
- 'backgroundOpacity': bgOpacity,
- 'textOpacity': textOpacity,
- 'windowOpacity': windowOpacity,
- 'edgeStyle': textEdge,
- 'fontFamily': fontFamily,
- 'color': fgColor,
- 'backgroundColor': bgColor,
- 'windowColor': windowColor,
- 'fontPercent': fontPercent
+ fontPercent,
+ fontFamily,
+ textOpacity,
+ windowColor,
+ windowOpacity,
+ backgroundOpacity: bgOpacity,
+ edgeStyle: textEdge,
+ color: fgColor,
+ backgroundColor: bgColor
};
+
for (let name in result) {
if (result[name] === '' || result[name] === 'none' || (name === 'fontPercent' && result[name] === 1.00)) {
delete result[name];
@@ -167,7 +321,8 @@ class TextTrackSettings extends Component {
* @method restoreSettings
*/
restoreSettings() {
- let err, values;
+ let err;
+ let values;
try {
[err, values] = safeParseTuple(window.localStorage.getItem('vjs-text-track-settings'));
@@ -195,6 +350,7 @@ class TextTrackSettings extends Component {
}
let values = this.getValues();
+
try {
if (Object.getOwnPropertyNames(values).length > 0) {
window.localStorage.setItem('vjs-text-track-settings', JSON.stringify(values));
@@ -213,6 +369,7 @@ class TextTrackSettings extends Component {
*/
updateDisplay() {
let ttDisplay = this.player_.getChild('textTrackDisplay');
+
if (ttDisplay) {
ttDisplay.updateDisplay();
}
@@ -222,154 +379,4 @@ class TextTrackSettings extends Component {
Component.registerComponent('TextTrackSettings', TextTrackSettings);
-function getSelectedOptionValue(target) {
- let selectedOption;
- // not all browsers support selectedOptions, so, fallback to options
- if (target.selectedOptions) {
- selectedOption = target.selectedOptions[0];
- } else if (target.options) {
- selectedOption = target.options[target.options.selectedIndex];
- }
-
- return selectedOption.value;
-}
-
-function setSelectedOption(target, value) {
- if (!value) {
- return;
- }
-
- let i;
- for (i = 0; i < target.options.length; i++) {
- const option = target.options[i];
- if (option.value === value) {
- break;
- }
- }
-
- target.selectedIndex = i;
-}
-
-function captionOptionsMenuTemplate(uniqueId, dialogLabelId, dialogDescriptionId) {
-
- let template = `
-
-
Captions Settings Dialog
-
Beginning of dialog window. Escape will cancel and close the window.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
`;
-
- return template;
-}
-
export default TextTrackSettings;
diff --git a/src/js/tracks/text-track.js b/src/js/tracks/text-track.js
index 582734f3d7..de58a75d45 100644
--- a/src/js/tracks/text-track.js
+++ b/src/js/tracks/text-track.js
@@ -5,7 +5,6 @@ import TextTrackCueList from './text-track-cue-list';
import * as Fn from '../utils/fn.js';
import {TextTrackKind, TextTrackMode} from './track-enums';
import log from '../utils/log.js';
-import document from 'global/document';
import window from 'global/window';
import Track from './track.js';
import { isCrossOrigin } from '../utils/url.js';
@@ -42,12 +41,12 @@ const parseCues = function(srcContent, track) {
parser.parse(srcContent);
if (errors.length > 0) {
- if (console.groupCollapsed) {
- console.groupCollapsed(`Text Track parsing errors for ${track.src}`);
+ if (window.console && window.console.groupCollapsed) {
+ window.console.groupCollapsed(`Text Track parsing errors for ${track.src}`);
}
errors.forEach((error) => log.error(error));
- if (console.groupEnd) {
- console.groupEnd();
+ if (window.console && window.console.groupEnd) {
+ window.console.groupEnd();
}
}
@@ -82,6 +81,7 @@ const loadTrack = function(src, track) {
if (typeof window.WebVTT !== 'function') {
if (track.tech_) {
let loadHandler = () => parseCues(responseBody, track);
+
track.tech_.on('vttjsloaded', loadHandler);
track.tech_.on('vttjserror', () => {
log.error(`vttjs failed to load, stopping trying to process ${track.src}`);
@@ -142,6 +142,7 @@ class TextTrack extends Track {
// on IE8 this will be a document element
// for every other browser this will be a normal object
let tt = super(settings);
+
tt.tech_ = settings.tech;
if (browser.IS_IE8) {
@@ -159,6 +160,10 @@ class TextTrack extends Track {
let activeCues = new TextTrackCueList(tt.activeCues_);
let changed = false;
let timeupdateHandler = Fn.bind(tt, function() {
+
+ // Accessing this.activeCues for the side-effects of updating itself
+ // due to it's nature as a getter function. Do not remove or cues will
+ // stop updating!
this.activeCues;
if (changed) {
this.trigger('cuechange');
diff --git a/src/js/tracks/track-enums.js b/src/js/tracks/track-enums.js
index ecab4dd4b3..e11d0d1c81 100644
--- a/src/js/tracks/track-enums.js
+++ b/src/js/tracks/track-enums.js
@@ -21,7 +21,7 @@ const VideoTrackKind = {
main: 'main',
sign: 'sign',
subtitles: 'subtitles',
- commentary: 'commentary',
+ commentary: 'commentary'
};
/**
@@ -38,12 +38,12 @@ const VideoTrackKind = {
* };
*/
const AudioTrackKind = {
- alternative: 'alternative',
- descriptions: 'descriptions',
- main: 'main',
+ 'alternative': 'alternative',
+ 'descriptions': 'descriptions',
+ 'main': 'main',
'main-desc': 'main-desc',
- translation: 'translation',
- commentary: 'commentary',
+ 'translation': 'translation',
+ 'commentary': 'commentary'
};
/**
@@ -65,8 +65,6 @@ const TextTrackKind = {
metadata: 'metadata'
};
-
-
/**
* https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackmode
*
@@ -78,9 +76,4 @@ const TextTrackMode = {
showing: 'showing'
};
-/* jshint ignore:start */
-// we ignore jshint here because it does not see
-// AudioTrackKind as defined here
export default { VideoTrackKind, AudioTrackKind, TextTrackKind, TextTrackMode };
-/* jshint ignore:end */
-
diff --git a/src/js/tracks/track-list.js b/src/js/tracks/track-list.js
index 3d15e164b3..b61b4c43c5 100644
--- a/src/js/tracks/track-list.js
+++ b/src/js/tracks/track-list.js
@@ -2,7 +2,6 @@
* @file track-list.js
*/
import EventTarget from '../event-target';
-import * as Fn from '../utils/fn.js';
import * as browser from '../utils/browser.js';
import document from 'global/document';
@@ -20,7 +19,7 @@ class TrackList extends EventTarget {
constructor(tracks = [], list = null) {
super();
if (!list) {
- list = this;
+ list = this; // eslint-disable-line
if (browser.IS_IE8) {
list = document.createElement('custom');
for (let prop in TrackList.prototype) {
@@ -119,6 +118,7 @@ class TrackList extends EventTarget {
for (let i = 0, l = this.length; i < l; i++) {
let track = this[i];
+
if (track.id === id) {
result = track;
break;
diff --git a/src/js/tracks/track.js b/src/js/tracks/track.js
index 8c8a115350..a347fa60d8 100644
--- a/src/js/tracks/track.js
+++ b/src/js/tracks/track.js
@@ -19,7 +19,8 @@ class Track extends EventTarget {
constructor(options = {}) {
super();
- let track = this;
+ let track = this; // eslint-disable-line
+
if (browser.IS_IE8) {
track = document.createElement('custom');
for (let prop in Track.prototype) {
@@ -38,7 +39,9 @@ class Track extends EventTarget {
for (let key in trackProps) {
Object.defineProperty(track, key, {
- get() { return trackProps[key]; },
+ get() {
+ return trackProps[key];
+ },
set() {}
});
}
diff --git a/src/js/tracks/video-track.js b/src/js/tracks/video-track.js
index fe8f172f53..deeb9c2794 100644
--- a/src/js/tracks/video-track.js
+++ b/src/js/tracks/video-track.js
@@ -38,7 +38,9 @@ class VideoTrack extends Track {
}
Object.defineProperty(track, 'selected', {
- get() { return selected; },
+ get() {
+ return selected;
+ },
set(newSelected) {
// an invalid or unchanged value
if (typeof newSelected !== 'boolean' || newSelected === selected) {
diff --git a/src/js/utils/browser.js b/src/js/utils/browser.js
index 9bad972b40..70ce027c54 100644
--- a/src/js/utils/browser.js
+++ b/src/js/utils/browser.js
@@ -24,18 +24,21 @@ export const IS_IPHONE = (/iPhone/i).test(USER_AGENT) && !IS_IPAD;
export const IS_IPOD = (/iPod/i).test(USER_AGENT);
export const IS_IOS = IS_IPHONE || IS_IPAD || IS_IPOD;
-export const IOS_VERSION = (function(){
- var match = USER_AGENT.match(/OS (\d+)_/i);
- if (match && match[1]) { return match[1]; }
-})();
+export const IOS_VERSION = (function() {
+ let match = USER_AGENT.match(/OS (\d+)_/i);
+
+ if (match && match[1]) {
+ return match[1];
+ }
+}());
export const IS_ANDROID = (/Android/i).test(USER_AGENT);
export const ANDROID_VERSION = (function() {
// This matches Android Major.Minor.Patch versions
// ANDROID_VERSION is Major.Minor as a Number, if Minor isn't available, then only Major is returned
- var match = USER_AGENT.match(/Android (\d+)(?:\.(\d+))?(?:\.(\d+))*/i),
- major,
- minor;
+ let match = USER_AGENT.match(/Android (\d+)(?:\.(\d+))?(?:\.(\d+))*/i);
+ let major;
+ let minor;
if (!match) {
return null;
@@ -48,10 +51,10 @@ export const ANDROID_VERSION = (function() {
return parseFloat(match[1] + '.' + match[2]);
} else if (major) {
return major;
- } else {
- return null;
}
-})();
+ return null;
+}());
+
// Old Android is defined as Version older than 2.3, and requiring a webkit version of the android browser
export const IS_OLD_ANDROID = IS_ANDROID && (/webkit/i).test(USER_AGENT) && ANDROID_VERSION < 2.3;
export const IS_NATIVE_ANDROID = IS_ANDROID && ANDROID_VERSION < 5 && appleWebkitVersion < 537;
@@ -60,9 +63,9 @@ export const IS_FIREFOX = (/Firefox/i).test(USER_AGENT);
export const IS_EDGE = (/Edge/i).test(USER_AGENT);
export const IS_CHROME = !IS_EDGE && (/Chrome/i).test(USER_AGENT);
export const IS_IE8 = (/MSIE\s8\.0/).test(USER_AGENT);
-export const IE_VERSION = (function(result){
+export const IE_VERSION = (function(result) {
return result && parseFloat(result[1]);
-})((/MSIE\s(\d+)\.\d/).exec(USER_AGENT));
+}((/MSIE\s(\d+)\.\d/).exec(USER_AGENT)));
export const TOUCH_ENABLED = !!(('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch);
export const BACKGROUND_SIZE_SUPPORTED = 'backgroundSize' in document.createElement('video').style;
diff --git a/src/js/utils/buffer.js b/src/js/utils/buffer.js
index 063a9ec95c..4a303aaa25 100644
--- a/src/js/utils/buffer.js
+++ b/src/js/utils/buffer.js
@@ -13,8 +13,9 @@ import { createTimeRange } from './time-ranges.js';
* @function bufferedPercent
*/
export function bufferedPercent(buffered, duration) {
- var bufferedDuration = 0,
- start, end;
+ let bufferedDuration = 0;
+ let start;
+ let end;
if (!duration) {
return 0;
@@ -24,9 +25,9 @@ export function bufferedPercent(buffered, duration) {
buffered = createTimeRange(0, 0);
}
- for (let i = 0; i < buffered.length; i++){
+ for (let i = 0; i < buffered.length; i++) {
start = buffered.start(i);
- end = buffered.end(i);
+ end = buffered.end(i);
// buffered end can be bigger than duration by a very small fraction
if (end > duration) {
diff --git a/src/js/utils/dom.js b/src/js/utils/dom.js
index 3d8fb51679..4fe03202fe 100644
--- a/src/js/utils/dom.js
+++ b/src/js/utils/dom.js
@@ -3,7 +3,7 @@
*/
import document from 'global/document';
import window from 'global/window';
-import * as Guid from './guid.js';
+import * as Guid from './guid.js';
import log from './log.js';
import tsml from 'tsml';
@@ -14,7 +14,7 @@ import tsml from 'tsml';
* @return {Boolean}
*/
function isNonBlankString(str) {
- return typeof str === 'string' && /\S/.test(str);
+ return typeof str === 'string' && (/\S/).test(str);
}
/**
@@ -25,7 +25,7 @@ function isNonBlankString(str) {
* @return {Boolean}
*/
function throwIfWhitespace(str) {
- if (/\s/.test(str)) {
+ if ((/\s/).test(str)) {
throw new Error('class has illegal whitespace characters');
}
}
@@ -40,6 +40,17 @@ function classRegExp(className) {
return new RegExp('(^|\\s)' + className + '($|\\s)');
}
+/**
+ * Determines, via duck typing, whether or not a value is a DOM element.
+ *
+ * @function isEl
+ * @param {Mixed} value
+ * @return {Boolean}
+ */
+export function isEl(value) {
+ return !!value && typeof value === 'object' && value.nodeType === 1;
+}
+
/**
* Creates functions to query the DOM using a given method.
*
@@ -49,7 +60,7 @@ function classRegExp(className) {
* @return {Function}
*/
function createQuerier(method) {
- return function (selector, context) {
+ return function(selector, context) {
if (!isNonBlankString(selector)) {
return document[method](null);
}
@@ -68,7 +79,7 @@ function createQuerier(method) {
* @return {Element} Element with supplied ID
* @function getEl
*/
-export function getEl(id){
+export function getEl(id) {
if (id.indexOf('#') === 0) {
id = id.slice(1);
}
@@ -85,10 +96,10 @@ export function getEl(id){
* @return {Element}
* @function createEl
*/
-export function createEl(tagName='div', properties={}, attributes={}){
+export function createEl(tagName = 'div', properties = {}, attributes = {}) {
let el = document.createElement(tagName);
- Object.getOwnPropertyNames(properties).forEach(function(propName){
+ Object.getOwnPropertyNames(properties).forEach(function(propName) {
let val = properties[propName];
// See #2176
@@ -104,8 +115,7 @@ export function createEl(tagName='div', properties={}, attributes={}){
}
});
- Object.getOwnPropertyNames(attributes).forEach(function(attrName){
- let val = attributes[attrName];
+ Object.getOwnPropertyNames(attributes).forEach(function(attrName) {
el.setAttribute(attrName, attributes[attrName]);
});
@@ -136,7 +146,7 @@ export function textContent(el, text) {
* @private
* @function insertElFirst
*/
-export function insertElFirst(child, parent){
+export function insertElFirst(child, parent) {
if (parent.firstChild) {
parent.insertBefore(child, parent.firstChild);
} else {
@@ -222,7 +232,7 @@ export function removeElData(el) {
// Remove the elIdAttr property from the DOM node
try {
delete el[elIdAttr];
- } catch(e) {
+ } catch (e) {
if (el.removeAttribute) {
el.removeAttribute(elIdAttr);
} else {
@@ -242,10 +252,9 @@ export function removeElData(el) {
export function hasElClass(element, classToCheck) {
if (element.classList) {
return element.classList.contains(classToCheck);
- } else {
- throwIfWhitespace(classToCheck);
- return classRegExp(classToCheck).test(element.className);
}
+ throwIfWhitespace(classToCheck);
+ return classRegExp(classToCheck).test(element.className);
}
/**
@@ -339,7 +348,7 @@ export function toggleElClass(element, classToToggle, predicate) {
* @function setElAttributes
*/
export function setElAttributes(el, attributes) {
- Object.getOwnPropertyNames(attributes).forEach(function(attrName){
+ Object.getOwnPropertyNames(attributes).forEach(function(attrName) {
let attrValue = attributes[attrName];
if (attrValue === null || typeof attrValue === 'undefined' || attrValue === false) {
@@ -362,25 +371,29 @@ export function setElAttributes(el, attributes) {
* @function getElAttributes
*/
export function getElAttributes(tag) {
- var obj, knownBooleans, attrs, attrName, attrVal;
+ let obj;
+ let knownBooleans;
+ let attrs;
+ let attrName;
+ let attrVal;
obj = {};
// known boolean attributes
// we can check for matching boolean properties, but older browsers
// won't know about HTML5 boolean attributes that we still read from
- knownBooleans = ','+'autoplay,controls,loop,muted,default'+',';
+ knownBooleans = ',' + 'autoplay,controls,loop,muted,default' + ',';
if (tag && tag.attributes && tag.attributes.length > 0) {
attrs = tag.attributes;
- for (var i = attrs.length - 1; i >= 0; i--) {
+ for (let i = attrs.length - 1; i >= 0; i--) {
attrName = attrs[i].name;
attrVal = attrs[i].value;
// check for known booleans
// the matching element property will return a value for typeof
- if (typeof tag[attrName] === 'boolean' || knownBooleans.indexOf(','+attrName+',') !== -1) {
+ if (typeof tag[attrName] === 'boolean' || knownBooleans.indexOf(',' + attrName + ',') !== -1) {
// the value of an included boolean attribute is typically an empty
// string ('') which would equal false if we just check for a false value.
// we also don't want support bad code like autoplay='false'
@@ -492,17 +505,6 @@ export function getPointerPosition(el, event) {
return position;
}
-/**
- * Determines, via duck typing, whether or not a value is a DOM element.
- *
- * @function isEl
- * @param {Mixed} value
- * @return {Boolean}
- */
-export function isEl(value) {
- return !!value && typeof value === 'object' && value.nodeType === 1;
-}
-
/**
* Determines, via duck typing, whether or not a value is a text node.
*
@@ -577,7 +579,7 @@ export function normalizeContent(content) {
return value;
}
- if (typeof value === 'string' && /\S/.test(value)) {
+ if (typeof value === 'string' && (/\S/).test(value)) {
return document.createTextNode(value);
}
}).filter(value => value);
diff --git a/src/js/utils/events.js b/src/js/utils/events.js
index 4c9ca211d1..ab44f22f49 100644
--- a/src/js/utils/events.js
+++ b/src/js/utils/events.js
@@ -7,11 +7,193 @@
* 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';
+/**
+ * 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) {
+ let data = Dom.getElData(elem);
+
+ // Remove the events of a particular type if there are none left
+ if (data.handlers[type].length === 0) {
+ delete data.handlers[type];
+ // data.handlers[type] = null;
+ // Setting to null was causing an error with data.handlers
+
+ // Remove the meta-handler from the element
+ if (elem.removeEventListener) {
+ elem.removeEventListener(type, data.dispatcher, false);
+ } else if (elem.detachEvent) {
+ elem.detachEvent('on' + type, data.dispatcher);
+ }
+ }
+
+ // Remove the events object if there are no types left
+ if (Object.getOwnPropertyNames(data.handlers).length <= 0) {
+ delete data.handlers;
+ delete data.dispatcher;
+ delete data.disabled;
+ }
+
+ // Finally remove the element data if there is no data left
+ if (Object.getOwnPropertyNames(data).length === 0) {
+ Dom.removeElData(elem);
+ }
+}
+
+/**
+ * Loops through an array of event types and calls the requested method for each type.
+ *
+ * @param {Function} fn The event method we want to use.
+ * @param {Element|Object} elem Element or object to bind listeners to
+ * @param {String} type Type of event to bind to.
+ * @param {Function} callback Event listener.
+ * @private
+ * @function _handleMultipleEvents
+ */
+function _handleMultipleEvents(fn, elem, types, callback) {
+ types.forEach(function(type) {
+ // Call the event method for each one of the types
+ fn(elem, type, callback);
+ });
+}
+
+/**
+ * Fix a native event to have standard property values
+ *
+ * @param {Object} event Event object to fix
+ * @return {Object}
+ * @private
+ * @method fixEvent
+ */
+export function fixEvent(event) {
+
+ function returnTrue() {
+ return true;
+ }
+
+ function returnFalse() {
+ return false;
+ }
+
+ // Test if fixing up is needed
+ // Used to check if !event.stopPropagation instead of isPropagationStopped
+ // But native events return true for stopPropagation, but don't have
+ // other expected methods like isPropagationStopped. Seems to be a problem
+ // with the Javascript Ninja code. So we're just overriding all events now.
+ if (!event || !event.isPropagationStopped) {
+ let old = event || window.event;
+
+ event = {};
+ // Clone the old object so that we can modify the values event = {};
+ // IE8 Doesn't like when you mess with native event properties
+ // Firefox returns false for event.hasOwnProperty('type') and other props
+ // which makes copying more difficult.
+ // TODO: Probably best to create a whitelist of event props
+ for (let key in old) {
+ // Safari 6.0.3 warns you if you try to copy deprecated layerX/Y
+ // Chrome warns you if you try to copy deprecated keyboardEvent.keyLocation
+ // and webkitMovementX/Y
+ if (key !== 'layerX' && key !== 'layerY' && key !== 'keyLocation' &&
+ key !== 'webkitMovementX' && key !== 'webkitMovementY') {
+ // Chrome 32+ warns if you try to copy deprecated returnValue, but
+ // we still want to if preventDefault isn't supported (IE8).
+ if (!(key === 'returnValue' && old.preventDefault)) {
+ event[key] = old[key];
+ }
+ }
+ }
+
+ // The event occurred on this element
+ if (!event.target) {
+ event.target = event.srcElement || document;
+ }
+
+ // Handle which other element the event is related to
+ if (!event.relatedTarget) {
+ event.relatedTarget = event.fromElement === event.target ?
+ event.toElement :
+ event.fromElement;
+ }
+
+ // Stop the default browser action
+ event.preventDefault = function() {
+ if (old.preventDefault) {
+ old.preventDefault();
+ }
+ event.returnValue = false;
+ old.returnValue = false;
+ event.defaultPrevented = true;
+ };
+
+ event.defaultPrevented = false;
+
+ // Stop the event from bubbling
+ event.stopPropagation = function() {
+ if (old.stopPropagation) {
+ old.stopPropagation();
+ }
+ event.cancelBubble = true;
+ old.cancelBubble = true;
+ event.isPropagationStopped = returnTrue;
+ };
+
+ event.isPropagationStopped = returnFalse;
+
+ // Stop the event from bubbling and executing other handlers
+ event.stopImmediatePropagation = function() {
+ if (old.stopImmediatePropagation) {
+ old.stopImmediatePropagation();
+ }
+ event.isImmediatePropagationStopped = returnTrue;
+ event.stopPropagation();
+ };
+
+ event.isImmediatePropagationStopped = returnFalse;
+
+ // Handle mouse position
+ if (event.clientX != null) {
+ let doc = document.documentElement;
+ let body = document.body;
+
+ event.pageX = event.clientX +
+ (doc && doc.scrollLeft || body && body.scrollLeft || 0) -
+ (doc && doc.clientLeft || body && body.clientLeft || 0);
+ event.pageY = event.clientY +
+ (doc && doc.scrollTop || body && body.scrollTop || 0) -
+ (doc && doc.clientTop || body && body.clientTop || 0);
+ }
+
+ // Handle key presses
+ event.which = event.charCode || event.keyCode;
+
+ // Fix button for mouse clicks:
+ // 0 == left; 1 == middle; 2 == right
+ if (event.button != null) {
+
+ // The following is disabled because it does not pass videojs-standard
+ // and... yikes.
+ /* eslint-disable */
+ event.button = (event.button & 1 ? 0 :
+ (event.button & 4 ? 1 :
+ (event.button & 2 ? 2 : 0)));
+ /* eslint-enable */
+ }
+ }
+
+ // Returns fixed-up instance
+ return event;
+}
+
/**
* Add an event listener to element
* It stores the handler function in a separate cache object
@@ -23,7 +205,7 @@ import document from 'global/document';
* @param {Function} fn Event listener.
* @method on
*/
-export function on(elem, type, fn){
+export function on(elem, type, fn) {
if (Array.isArray(type)) {
return _handleMultipleEvents(on, elem, type, fn);
}
@@ -31,29 +213,38 @@ export function on(elem, type, fn){
let data = Dom.getElData(elem);
// We need a place to store all our handler data
- if (!data.handlers) data.handlers = {};
+ if (!data.handlers) {
+ data.handlers = {};
+ }
- if (!data.handlers[type]) data.handlers[type] = [];
+ if (!data.handlers[type]) {
+ data.handlers[type] = [];
+ }
- if (!fn.guid) fn.guid = Guid.newGUID();
+ if (!fn.guid) {
+ fn.guid = Guid.newGUID();
+ }
data.handlers[type].push(fn);
if (!data.dispatcher) {
data.disabled = false;
- data.dispatcher = function (event, hash){
+ data.dispatcher = function(event, hash) {
+
+ if (data.disabled) {
+ return;
+ }
- if (data.disabled) return;
event = fixEvent(event);
- var handlers = data.handlers[event.type];
+ let handlers = data.handlers[event.type];
if (handlers) {
// Copy handlers so if handlers are added/removed during the process it doesn't throw everything off.
- var handlersCopy = handlers.slice(0);
+ let handlersCopy = handlers.slice(0);
- for (var m = 0, n = handlersCopy.length; m < n; m++) {
+ for (let m = 0, n = handlersCopy.length; m < n; m++) {
if (event.isImmediatePropagationStopped()) {
break;
} else {
@@ -83,33 +274,41 @@ export function on(elem, type, fn){
*/
export function off(elem, type, fn) {
// Don't want to add a cache object through getElData if not needed
- if (!Dom.hasElData(elem)) return;
+ if (!Dom.hasElData(elem)) {
+ return;
+ }
let data = Dom.getElData(elem);
// If no events exist, nothing to unbind
- if (!data.handlers) { return; }
+ if (!data.handlers) {
+ return;
+ }
if (Array.isArray(type)) {
return _handleMultipleEvents(off, elem, type, fn);
}
// Utility function
- var removeType = function(t){
- data.handlers[t] = [];
- _cleanUpEvents(elem,t);
+ let removeType = function(t) {
+ data.handlers[t] = [];
+ _cleanUpEvents(elem, t);
};
// Are we removing all bound events?
if (!type) {
- for (let t in data.handlers) removeType(t);
+ for (let t in data.handlers) {
+ removeType(t);
+ }
return;
}
- var handlers = data.handlers[type];
+ let handlers = data.handlers[type];
// If no handlers exist, nothing to unbind
- if (!handlers) return;
+ if (!handlers) {
+ return;
+ }
// If no listener was provided, remove all listeners for type
if (!fn) {
@@ -142,14 +341,14 @@ export function trigger(elem, event, hash) {
// Fetches element data and a reference to the parent (for bubbling).
// Don't want to add a data object to cache for every parent,
// so checking hasElData first.
- var elemData = (Dom.hasElData(elem)) ? Dom.getElData(elem) : {};
- var parent = elem.parentNode || elem.ownerDocument;
+ let elemData = (Dom.hasElData(elem)) ? Dom.getElData(elem) : {};
+ let parent = elem.parentNode || elem.ownerDocument;
// type = event.type || event,
// handler;
// If an event name was passed as a string, creates an event out of it
if (typeof event === 'string') {
- event = { type:event, target:elem };
+ event = {type: event, target: elem};
}
// Normalizes the event properties.
event = fixEvent(event);
@@ -160,13 +359,13 @@ export function trigger(elem, event, hash) {
}
// Unless explicitly stopped or the event does not bubble (e.g. media events)
- // recursively calls this function to bubble the event up the DOM.
- if (parent && !event.isPropagationStopped() && event.bubbles === true) {
- trigger.call(null, parent, event, hash);
+ // recursively calls this function to bubble the event up the DOM.
+ if (parent && !event.isPropagationStopped() && event.bubbles === true) {
+ trigger.call(null, parent, event, hash);
// If at the top of the DOM, triggers the default action unless disabled.
} else if (!parent && !event.defaultPrevented) {
- var targetData = Dom.getElData(event.target);
+ let targetData = Dom.getElData(event.target);
// Checks if the target has a default action for this event.
if (event.target[event.type]) {
@@ -197,182 +396,12 @@ export function one(elem, type, fn) {
if (Array.isArray(type)) {
return _handleMultipleEvents(one, elem, type, fn);
}
- var func = function(){
+ let func = function() {
off(elem, type, func);
fn.apply(this, arguments);
};
+
// copy the guid to the new function so it can removed using the original function's ID
func.guid = fn.guid = fn.guid || Guid.newGUID();
on(elem, type, func);
}
-
-/**
- * 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) {
-
- function returnTrue() { return true; }
- function returnFalse() { return false; }
-
- // Test if fixing up is needed
- // Used to check if !event.stopPropagation instead of isPropagationStopped
- // But native events return true for stopPropagation, but don't have
- // other expected methods like isPropagationStopped. Seems to be a problem
- // with the Javascript Ninja code. So we're just overriding all events now.
- if (!event || !event.isPropagationStopped) {
- var old = event || window.event;
-
- event = {};
- // Clone the old object so that we can modify the values event = {};
- // IE8 Doesn't like when you mess with native event properties
- // Firefox returns false for event.hasOwnProperty('type') and other props
- // which makes copying more difficult.
- // TODO: Probably best to create a whitelist of event props
- for (var key in old) {
- // Safari 6.0.3 warns you if you try to copy deprecated layerX/Y
- // Chrome warns you if you try to copy deprecated keyboardEvent.keyLocation
- // and webkitMovementX/Y
- if (key !== 'layerX' && key !== 'layerY' && key !== 'keyLocation' &&
- key !== 'webkitMovementX' && key !== 'webkitMovementY') {
- // Chrome 32+ warns if you try to copy deprecated returnValue, but
- // we still want to if preventDefault isn't supported (IE8).
- if (!(key === 'returnValue' && old.preventDefault)) {
- event[key] = old[key];
- }
- }
- }
-
- // The event occurred on this element
- if (!event.target) {
- event.target = event.srcElement || document;
- }
-
- // Handle which other element the event is related to
- if (!event.relatedTarget) {
- event.relatedTarget = event.fromElement === event.target ?
- event.toElement :
- event.fromElement;
- }
-
- // Stop the default browser action
- event.preventDefault = function () {
- if (old.preventDefault) {
- old.preventDefault();
- }
- event.returnValue = false;
- old.returnValue = false;
- event.defaultPrevented = true;
- };
-
- event.defaultPrevented = false;
-
- // Stop the event from bubbling
- event.stopPropagation = function () {
- if (old.stopPropagation) {
- old.stopPropagation();
- }
- event.cancelBubble = true;
- old.cancelBubble = true;
- event.isPropagationStopped = returnTrue;
- };
-
- event.isPropagationStopped = returnFalse;
-
- // Stop the event from bubbling and executing other handlers
- event.stopImmediatePropagation = function () {
- if (old.stopImmediatePropagation) {
- old.stopImmediatePropagation();
- }
- event.isImmediatePropagationStopped = returnTrue;
- event.stopPropagation();
- };
-
- event.isImmediatePropagationStopped = returnFalse;
-
- // Handle mouse position
- if (event.clientX != null) {
- var doc = document.documentElement, body = document.body;
-
- event.pageX = event.clientX +
- (doc && doc.scrollLeft || body && body.scrollLeft || 0) -
- (doc && doc.clientLeft || body && body.clientLeft || 0);
- event.pageY = event.clientY +
- (doc && doc.scrollTop || body && body.scrollTop || 0) -
- (doc && doc.clientTop || body && body.clientTop || 0);
- }
-
- // Handle key presses
- event.which = event.charCode || event.keyCode;
-
- // Fix button for mouse clicks:
- // 0 == left; 1 == middle; 2 == right
- if (event.button != null) {
- event.button = (event.button & 1 ? 0 :
- (event.button & 4 ? 1 :
- (event.button & 2 ? 2 : 0)));
- }
- }
-
- // Returns fixed-up instance
- return 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);
-
- // Remove the events of a particular type if there are none left
- if (data.handlers[type].length === 0) {
- delete data.handlers[type];
- // data.handlers[type] = null;
- // Setting to null was causing an error with data.handlers
-
- // Remove the meta-handler from the element
- if (elem.removeEventListener) {
- elem.removeEventListener(type, data.dispatcher, false);
- } else if (elem.detachEvent) {
- elem.detachEvent('on' + type, data.dispatcher);
- }
- }
-
- // Remove the events object if there are no types left
- if (Object.getOwnPropertyNames(data.handlers).length <= 0) {
- delete data.handlers;
- delete data.dispatcher;
- delete data.disabled;
- }
-
- // Finally remove the element data if there is no data left
- if (Object.getOwnPropertyNames(data).length === 0) {
- Dom.removeElData(elem);
- }
-}
-
-/**
- * Loops through an array of event types and calls the requested method for each type.
- *
- * @param {Function} fn The event method we want to use.
- * @param {Element|Object} elem Element or object to bind listeners to
- * @param {String} type Type of event to bind to.
- * @param {Function} callback Event listener.
- * @private
- * @function _handleMultipleEvents
- */
-function _handleMultipleEvents(fn, elem, types, callback) {
- types.forEach(function(type) {
- //Call the event method for each one of the types
- fn(elem, type, callback);
- });
-}
diff --git a/src/js/utils/fn.js b/src/js/utils/fn.js
index 69bbe83ad8..f2d4d411f4 100644
--- a/src/js/utils/fn.js
+++ b/src/js/utils/fn.js
@@ -16,7 +16,9 @@ import { newGUID } from './guid.js';
*/
export const bind = function(context, fn, uid) {
// Make sure the function has a unique ID
- if (!fn.guid) { fn.guid = newGUID(); }
+ if (!fn.guid) {
+ fn.guid = newGUID();
+ }
// Create the new function that changes the context
let ret = function() {
diff --git a/src/js/utils/format-time.js b/src/js/utils/format-time.js
index dc6182c9c4..bd47c68079 100644
--- a/src/js/utils/format-time.js
+++ b/src/js/utils/format-time.js
@@ -11,7 +11,7 @@
* @private
* @function formatTime
*/
-function formatTime(seconds, guide=seconds) {
+function formatTime(seconds, guide = seconds) {
seconds = seconds < 0 ? 0 : seconds;
let s = Math.floor(seconds % 60);
let m = Math.floor(seconds / 60 % 60);
diff --git a/src/js/utils/guid.js b/src/js/utils/guid.js
index e832e7088b..3a124d8fc7 100644
--- a/src/js/utils/guid.js
+++ b/src/js/utils/guid.js
@@ -10,7 +10,7 @@ let _guid = 1;
/**
* Get the next unique ID
*
- * @return {String}
+ * @return {String}
* @function newGUID
*/
export function newGUID() {
diff --git a/src/js/utils/log.js b/src/js/utils/log.js
index 332cda6e73..fca15985b2 100644
--- a/src/js/utils/log.js
+++ b/src/js/utils/log.js
@@ -4,6 +4,8 @@
import window from 'global/window';
import {IE_VERSION} from './browser';
+let log;
+
/**
* Log messages to the console and history based on the type of message
*
@@ -16,7 +18,6 @@ import {IE_VERSION} from './browser';
* but this is exposed as a parameter to facilitate testing.
*/
export const logByType = (type, args, stringify = !!IE_VERSION && IE_VERSION < 11) => {
- const console = window.console;
// If there's no console then don't try to output messages, but they will
// still be stored in `log.history`.
@@ -24,7 +25,7 @@ export const logByType = (type, args, stringify = !!IE_VERSION && IE_VERSION < 1
// Was setting these once outside of this function, but containing them
// in the function makes it easier to test cases where console doesn't exist
// when the module is executed.
- const fn = console && console[type] || function(){};
+ const fn = window.console && window.console[type] || function() {};
if (type !== 'log') {
@@ -45,7 +46,9 @@ export const logByType = (type, args, stringify = !!IE_VERSION && IE_VERSION < 1
if (a && typeof a === 'object' || Array.isArray(a)) {
try {
return JSON.stringify(a);
- } catch (x) {}
+ } catch (x) {
+ return String(a);
+ }
}
// Cast to string before joining, so we get null and undefined explicitly
@@ -68,9 +71,9 @@ export const logByType = (type, args, stringify = !!IE_VERSION && IE_VERSION < 1
*
* @function log
*/
-function log(...args) {
+log = function(...args) {
logByType('log', args);
-}
+};
/**
* Keep a history of log messages
@@ -93,5 +96,4 @@ log.error = (...args) => logByType('error', args);
*/
log.warn = (...args) => logByType('warn', args);
-
export default log;
diff --git a/src/js/utils/merge-options.js b/src/js/utils/merge-options.js
index ac3558a9ed..c5493b2841 100644
--- a/src/js/utils/merge-options.js
+++ b/src/js/utils/merge-options.js
@@ -4,12 +4,14 @@
import merge from 'lodash-compat/object/merge';
function isPlain(obj) {
- return !!obj
- && typeof obj === 'object'
- && obj.toString() === '[object Object]'
- && obj.constructor === Object;
+ return !!obj &&
+ typeof obj === 'object' &&
+ obj.toString() === '[object Object]' &&
+ obj.constructor === Object;
}
+let mergeOptions;
+
/**
* Merge customizer. video.js simply overwrites non-simple objects
* (like arrays) instead of attempting to overlay them.
@@ -41,7 +43,7 @@ const customizer = function(destination, source) {
* provided objects
* @function mergeOptions
*/
-export default function mergeOptions() {
+mergeOptions = function() {
// contruct the call dynamically to handle the variable number of
// objects to merge
let args = Array.prototype.slice.call(arguments);
@@ -57,4 +59,6 @@ export default function mergeOptions() {
// return the mutated result object
return args[0];
-}
+};
+
+export default mergeOptions;
diff --git a/src/js/utils/stylesheet.js b/src/js/utils/stylesheet.js
index b06f2bc3d8..d00214b599 100644
--- a/src/js/utils/stylesheet.js
+++ b/src/js/utils/stylesheet.js
@@ -2,6 +2,7 @@ import document from 'global/document';
export let createStyleElement = function(className) {
let style = document.createElement('style');
+
style.className = className;
return style;
diff --git a/src/js/utils/time-ranges.js b/src/js/utils/time-ranges.js
index 1f17619665..f81c71db1c 100644
--- a/src/js/utils/time-ranges.js
+++ b/src/js/utils/time-ranges.js
@@ -1,37 +1,28 @@
import log from './log.js';
-/**
- * @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|Array)} Start of a single range or an array of ranges
- * @param {Number} End of a single range
- * @private
- * @method createTimeRanges
- */
-export function createTimeRanges(start, end){
- if (Array.isArray(start)) {
- return createTimeRangesObj(start);
- } else if (start === undefined || end === undefined) {
- return createTimeRangesObj();
+function rangeCheck(fnName, index, maxIndex) {
+ if (index < 0 || index > maxIndex) {
+ throw new Error(`Failed to execute '${fnName}' on 'TimeRanges': The index provided (${index}) is greater than or equal to the maximum bound (${maxIndex}).`);
}
- return createTimeRangesObj([[start, end]]);
}
-export { createTimeRanges as createTimeRange };
+function getRange(fnName, valueIndex, ranges, rangeIndex) {
+ if (rangeIndex === undefined) {
+ log.warn(`DEPRECATED: Function '${fnName}' on 'TimeRanges' called without an index argument.`);
+ rangeIndex = 0;
+ }
+ rangeCheck(fnName, rangeIndex, ranges.length - 1);
+ return ranges[rangeIndex][valueIndex];
+}
-function createTimeRangesObj(ranges){
+function createTimeRangesObj(ranges) {
if (ranges === undefined || ranges.length === 0) {
return {
length: 0,
- start: function() {
+ start() {
throw new Error('This TimeRanges object is empty');
},
- end: function() {
+ end() {
throw new Error('This TimeRanges object is empty');
}
};
@@ -43,17 +34,26 @@ function createTimeRangesObj(ranges){
};
}
-function getRange(fnName, valueIndex, ranges, rangeIndex){
- if (rangeIndex === undefined) {
- log.warn(`DEPRECATED: Function '${fnName}' on 'TimeRanges' called without an index argument.`);
- rangeIndex = 0;
+/**
+ * @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|Array)} Start of a single range or an array of ranges
+ * @param {Number} End of a single range
+ * @private
+ * @method createTimeRanges
+ */
+export function createTimeRanges(start, end) {
+ if (Array.isArray(start)) {
+ return createTimeRangesObj(start);
+ } else if (start === undefined || end === undefined) {
+ return createTimeRangesObj();
}
- rangeCheck(fnName, rangeIndex, ranges.length - 1);
- return ranges[rangeIndex][valueIndex];
+ return createTimeRangesObj([[start, end]]);
}
-function rangeCheck(fnName, index, maxIndex){
- if (index < 0 || index > maxIndex) {
- throw new Error(`Failed to execute '${fnName}' on 'TimeRanges': The index provided (${index}) is greater than or equal to the maximum bound (${maxIndex}).`);
- }
-}
+export { createTimeRanges as createTimeRange };
diff --git a/src/js/utils/to-title-case.js b/src/js/utils/to-title-case.js
index f3984f8190..c9f97b88e1 100644
--- a/src/js/utils/to-title-case.js
+++ b/src/js/utils/to-title-case.js
@@ -8,7 +8,7 @@
* @private
* @method toTitleCase
*/
-function toTitleCase(string){
+function toTitleCase(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
diff --git a/src/js/utils/url.js b/src/js/utils/url.js
index 6532c28fe4..e0e9b9f2cd 100644
--- a/src/js/utils/url.js
+++ b/src/js/utils/url.js
@@ -16,6 +16,7 @@ export const parseUrl = function(url) {
// add the url to an anchor and let the browser parse the URL
let a = document.createElement('a');
+
a.href = url;
// IE8 (and 9?) Fix
@@ -23,6 +24,7 @@ export const parseUrl = function(url) {
// added to the body, and an innerHTML is needed to trigger the parsing
let addToBody = (a.host === '' && a.protocol !== 'file:');
let div;
+
if (addToBody) {
div = document.createElement('div');
div.innerHTML = ``;
@@ -36,7 +38,8 @@ export const parseUrl = function(url) {
// This is also needed for IE8 because the anchor loses its
// properties when it's removed from the dom
let details = {};
- for (var i = 0; i < props.length; i++) {
+
+ for (let i = 0; i < props.length; i++) {
details[props[i]] = a[props[i]];
}
@@ -45,6 +48,7 @@ export const parseUrl = function(url) {
if (details.protocol === 'http:') {
details.host = details.host.replace(/:80$/, '');
}
+
if (details.protocol === 'https:') {
details.host = details.host.replace(/:443$/, '');
}
@@ -65,11 +69,12 @@ export const parseUrl = function(url) {
* @private
* @method getAbsoluteURL
*/
-export const getAbsoluteURL = function(url){
+export const getAbsoluteURL = function(url) {
// Check if absolute URL
if (!url.match(/^https?:\/\//)) {
// Convert to absolute URL. Flash hosted off-site needs an absolute URL.
let div = document.createElement('div');
+
div.innerHTML = `x`;
url = div.firstChild.href;
}
@@ -85,7 +90,7 @@ export const getAbsoluteURL = function(url){
* @method getFileExtension
*/
export const getFileExtension = function(path) {
- if(typeof path === 'string'){
+ if (typeof path === 'string') {
let splitPathRe = /^(\/?)([\s\S]*?)((?:\.{1,2}|[^\/]+?)(\.([^\.\/\?]+)))(?:[\/]*|[\?].*)$/i;
let pathParts = splitPathRe.exec(path);
diff --git a/src/js/video.js b/src/js/video.js
index e9ac832f47..f9fe04c8b6 100644
--- a/src/js/video.js
+++ b/src/js/video.js
@@ -1,6 +1,9 @@
/**
* @file video.js
*/
+
+/* global define */
+
import window from 'global/window';
import document from 'global/document';
import * as setup from './setup';
@@ -28,8 +31,6 @@ import xhr from 'xhr';
// Include the built-in techs
import Tech from './tech/tech.js';
-import Html5 from './tech/html5.js';
-import Flash from './tech/flash.js';
// HTML5 Element Shim for IE8
if (typeof HTMLVideoElement === 'undefined') {
@@ -53,8 +54,8 @@ if (typeof HTMLVideoElement === 'undefined') {
* @mixes videojs
* @method videojs
*/
-function videojs(id, options, ready){
- let tag; // Element of ID
+function videojs(id, options, ready) {
+ let tag;
// Allow for element or ID to be passed in
// String ID
@@ -78,11 +79,10 @@ function videojs(id, options, ready){
}
return videojs.getPlayers()[id];
+ }
// Otherwise get element for ID
- } else {
- tag = Dom.getEl(id);
- }
+ tag = Dom.getEl(id);
// ID is a media element
} else {
@@ -90,13 +90,14 @@ function videojs(id, options, ready){
}
// Check for a useable element
- if (!tag || !tag.nodeName) { // re: nodeName, could be a box div also
- throw new TypeError('The element or ID supplied is not valid. (videojs)'); // Returns
+ // re: nodeName, could be a box div also
+ if (!tag || !tag.nodeName) {
+ throw new TypeError('The element or ID supplied is not valid. (videojs)');
}
// Element may have a player attr referring to an already created player instance.
// If not, set up a new player and return the instance.
- return tag['player'] || Player.players[tag.playerId] || new Player(tag, options, ready);
+ return tag.player || Player.players[tag.playerId] || new Player(tag, options, ready);
}
// Add default styles
@@ -106,6 +107,7 @@ if (window.VIDEOJS_NO_DYNAMIC_STYLE !== true) {
if (!style) {
style = stylesheet.createStyleElement('vjs-styles-defaults');
let head = Dom.$('head');
+
head.insertBefore(style, head.firstChild);
stylesheet.setTextContent(style, `
.video-js {
@@ -121,7 +123,8 @@ if (window.VIDEOJS_NO_DYNAMIC_STYLE !== true) {
}
// Run Auto-load players
-// 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)
+// 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);
/*
@@ -269,12 +272,12 @@ videojs.TOUCH_ENABLED = browser.TOUCH_ENABLED;
* Mimics ES6 subclassing with the `extend` keyword
* ```js
* // Create a basic javascript 'class'
- * function MyClass(name){
+ * function MyClass(name) {
* // Set a property at initialization
* this.myName = name;
* }
* // Create an instance method
- * MyClass.prototype.sayMyName = function(){
+ * MyClass.prototype.sayMyName = function() {
* alert(this.myName);
* };
* // Subclass the exisitng class and change the name
@@ -337,12 +340,12 @@ videojs.mergeOptions = mergeOptions;
/**
* Change the context (this) of a function
*
- * videojs.bind(newContext, function(){
+ * videojs.bind(newContext, function() {
* this === newContext
* });
*
* NOTE: as of v5.0 we require an ES5 shim, so you should use the native
- * `function(){}.bind(newContext);` instead of this.
+ * `function() {}.bind(newContext);` instead of this.
*
* @param {*} context The object to bind as scope
* @param {Function} fn The function to be bound to a scope
@@ -365,7 +368,7 @@ videojs.bind = Fn.bind;
* var player = this;
* var alertText = myPluginOptions.text || 'Player is playing!'
*
- * player.on('play', function(){
+ * player.on('play', function() {
* alert(alertText);
* });
* });
@@ -410,7 +413,7 @@ videojs.plugin = plugin;
* @mixes videojs
* @method addLanguage
*/
-videojs.addLanguage = function(code, data){
+videojs.addLanguage = function(code, data) {
code = ('' + code).toLowerCase();
return merge(videojs.options.languages, { [code]: data })[code];
};
@@ -721,12 +724,12 @@ videojs.insertContent = Dom.insertContent;
* still support requirejs and browserify. This also needs to be closure
* compiler compatible, so string keys are used.
*/
-if (typeof define === 'function' && define['amd']) {
- define('videojs', [], function(){ return videojs; });
+if (typeof define === 'function' && define.amd) {
+ define('videojs', [], () => videojs);
// checking that module is an object too because of umdjs/umd#35
} else if (typeof exports === 'object' && typeof module === 'object') {
- module['exports'] = videojs;
+ module.exports = videojs;
}
export default videojs;