diff --git a/.gitignore b/.gitignore
index 71329df61..4f3d58320 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,4 @@
.DS_Store
-dist/*
build/files/*
build/temp/*
docs/api/*
@@ -26,3 +25,6 @@ sandbox/*
test/coverage/*
.coveralls.yml
+.sass-cache
+
+dist/*
diff --git a/.travis.yml b/.travis.yml
index f88fb55fb..8532b27da 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,6 +1,6 @@
language: node_js
node_js:
- - 0.10
+ - "iojs"
before_script:
- if [ "${TRAVIS_PULL_REQUEST}" = "false" ]; then curl https://gist.githubusercontent.com/santiycr/5139565/raw/sauce_connect_setup.sh | bash; fi
before_install:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6c5350f12..e8c11b135 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,17 @@ CHANGELOG
* @dn5 Added new translations (Bosnian, Serbian, Croatian) ([view](https://github.com/videojs/video.js/pull/1897))
* @mmcc (and others) converted the whole project to use ES6, Babel and Browserify ([view](https://github.com/videojs/video.js/pull/1976))
* @heff converted all classes to use ES6 classes ([view](https://github.com/videojs/video.js/pull/1993))
+* @mmcc added ES6 default args and template strings ([view](https://github.com/videojs/video.js/pull/2015))
+* @dconnolly replaced JSON.parse with a safe non-eval JSON parse ([view](https://github.com/videojs/video.js/pull/2077))
+* @mmcc added a new default skin, switched to SASS, modified the html ([view](https://github.com/videojs/video.js/pull/1999))
+* @gkatsev removed event.isDefaultPrevented in favor of event.defaultPrevented ([view](https://github.com/videojs/video.js/pull/2081))
+* @heff added and `extends` function for external subclassing ([view](https://github.com/videojs/video.js/pull/2078))
+* @forbesjo added the `scrubbing` property ([view](https://github.com/videojs/video.js/pull/2080))
+* @heff switched to border-box sizing for all player elements ([view](https://github.com/videojs/video.js/pull/2082))
+* @forbesjo added a vjs-button class to button controls ([view](https://github.com/videojs/video.js/pull/2084))
+* @bc-bbay Load plugins before controls ([view](https://github.com/videojs/video.js/pull/2094))
+* @bc-bbay rename onEvent methods to handleEvent ([view](https://github.com/videojs/video.js/pull/2093))
+* @dmlap added an error message if techOrder is not in options ([view](https://github.com/videojs/video.js/pull/2097))
--------------------
diff --git a/Gruntfile.js b/Gruntfile.js
index b2ff8205f..733cff1de 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -53,15 +53,27 @@ module.exports = function(grunt) {
},
dist: {},
watch: {
- files: [ 'src/**/*', 'test/unit/**/*.js', 'Gruntfile.js' ],
- tasks: 'dev'
+ default: {
+ files: [ 'src/**/*', 'test/unit/**/*.js', 'Gruntfile.js' ],
+ tasks: 'dev'
+ },
+ skin: {
+ files: ['src/css/**/*'],
+ tasks: 'sass'
+ }
},
connect: {
- dev: {
+ preview: {
options: {
port: 9999,
keepalive: true
}
+ },
+ dev: {
+ options: {
+ port: 9999,
+ livereload: true
+ }
}
},
copy: {
@@ -143,10 +155,10 @@ module.exports = function(grunt) {
ext: '.min.css'
}
},
- less: {
- dev: {
+ sass: {
+ dist: {
files: {
- 'build/temp/video-js.css': 'src/css/video-js.less'
+ 'build/temp/video-js.css': 'src/css/video-js.scss'
}
}
},
@@ -226,6 +238,12 @@ module.exports = function(grunt) {
},
src: ['package.json', 'bower.json', 'component.json']
},
+ prerelease: {
+ options: {
+ release: 'prerelease'
+ },
+ src: ['package.json', 'bower.json', 'component.json']
+ },
css: {
options: {
prefix: '@version\\s*'
@@ -251,6 +269,21 @@ module.exports = function(grunt) {
}
},
browserify: {
+ options: {
+ transform: [
+ require('babelify').configure({
+ sourceMapRelative: './src/js'
+ }),
+ ['browserify-versionify', {
+ placeholder: '__VERSION__',
+ version: pkg.version
+ }],
+ ['browserify-versionify', {
+ placeholder: '__VERSION_NO_PATCH__',
+ version: version.majorMinor
+ }]
+ ]
+ },
build: {
files: {
'build/temp/video.js': ['src/js/video.js']
@@ -261,18 +294,17 @@ module.exports = function(grunt) {
standalone: 'videojs'
},
banner: license,
- transform: [
- require('babelify').configure({
- sourceMapRelative: './src/js'
- }),
- ['browserify-versionify', {
- placeholder: '__VERSION__',
- version: pkg.version
- }],
- ['browserify-versionify', {
- placeholder: '__VERSION_NO_PATCH__',
- version: version.majorMinor
- }]
+ plugin: [
+ [ 'browserify-derequire' ]
+ ]
+ }
+ },
+ test: {
+ files: {
+ 'build/temp/tests.js': [
+ 'test/globals-shim.js',
+ 'test/unit/**/*.js',
+ 'test/api/**.js'
]
}
},
@@ -288,18 +320,8 @@ module.exports = function(grunt) {
standalone: 'videojs'
},
banner: license,
- transform: [
- require('babelify').configure({
- sourceMapRelative: './src/js'
- }),
- ['browserify-versionify', {
- placeholder: '__VERSION__',
- version: pkg.version
- }],
- ['browserify-versionify', {
- placeholder: '__VERSION_NO_PATCH__',
- version: version.majorMinor
- }]
+ plugin: [
+ [ 'browserify-derequire' ]
]
}
}
@@ -313,6 +335,9 @@ module.exports = function(grunt) {
}
},
coveralls: {
+ options: {
+ force: true
+ },
all: {
src: 'test/coverage/lcov.info'
}
@@ -335,7 +360,7 @@ module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-contrib-cssmin');
- grunt.loadNpmTasks('grunt-contrib-less');
+ grunt.loadNpmTasks('grunt-sass');
grunt.loadNpmTasks('grunt-karma');
grunt.loadNpmTasks('videojs-doc-generator');
grunt.loadNpmTasks('grunt-zip');
@@ -360,7 +385,7 @@ module.exports = function(grunt) {
'concat:vtt',
'exorcise',
'uglify',
- 'less',
+ 'sass',
'version:css',
'cssmin',
'copy:fonts',
@@ -386,10 +411,13 @@ module.exports = function(grunt) {
grunt.registerTask('newtest', ['build', 'karma:chrome']);
// Default task.
- grunt.registerTask('default', ['build', 'test']);
+ grunt.registerTask('default', ['build', 'test-local']);
// Development watch task. Doing the minimum required.
- grunt.registerTask('dev', ['jshint', 'less', 'browserify:build', 'karma:chrome']);
+ grunt.registerTask('dev', ['connect:dev', 'jshint', 'sass', 'browserify:build', 'karma:chrome']);
+
+ // Skin development watch task.
+ grunt.registerTask('skin-dev', ['connect:dev', 'watch:skin']);
// Tests.
// We want to run things a little differently if it's coming from Travis vs local
diff --git a/README.md b/README.md
index a454f26ef..7484b4de7 100644
--- a/README.md
+++ b/README.md
@@ -61,4 +61,4 @@ To build your own custom version read the section on [contributing code](CONTRIB
Video.js is licensed under the Apache License, Version 2.0. [View the license file](LICENSE)
-Copyright 2014 Brightcove, Inc.
+Copyright 2014-2015 Brightcove, Inc.
diff --git a/bower.json b/bower.json
index 6e826a4de..4ebf1484e 100644
--- a/bower.json
+++ b/bower.json
@@ -1,7 +1,7 @@
{
"name": "video.js",
"description": "An HTML5 and Flash video player with a common API and skin for both.",
- "version": "4.12.5",
+ "version": "5.0.0-1",
"main": [
"dist/video-js/video.js",
"dist/video-js/video-js.css",
diff --git a/build/tasks/style-injection.js b/build/tasks/style-injection.js
new file mode 100644
index 000000000..9a2331b00
--- /dev/null
+++ b/build/tasks/style-injection.js
@@ -0,0 +1,11 @@
+module.exports = function(grunt) {
+ grunt.registerTask('addStyleInjection', 'Adding base style injection', function() {
+ var minifiedCss = grunt.file.read('build/files/video-js.min.css');
+ // We need to escape any strings
+ minifiedCss = minifiedCss.replace(/'/g, '\\\'');
+
+ var combinedJs = grunt.file.read('build/files/combined.video.js');
+ combinedJs = combinedJs.replace(/\{{GENERATED_STYLES}}/g, minifiedCss);
+ grunt.file.write('build/files/combined.video.js', combinedJs);
+ });
+};
diff --git a/component.json b/component.json
index 9f4903241..3360b2901 100644
--- a/component.json
+++ b/component.json
@@ -1,7 +1,7 @@
{
"name": "video.js",
"description": "An HTML5 and Flash video player with a common API and skin for both.",
- "version": "4.12.5",
+ "version": "5.0.0-1",
"keywords": [
"videojs",
"html5",
diff --git a/docs/examples/simple-embed/index.html b/docs/examples/simple-embed/index.html
index f34122870..091d931a2 100644
--- a/docs/examples/simple-embed/index.html
+++ b/docs/examples/simple-embed/index.html
@@ -4,13 +4,13 @@
Video.js | HTML5 Video Player
-
+
-
+
diff --git a/docs/guides/setup.md b/docs/guides/setup.md
index 6f1153794..c4f221068 100644
--- a/docs/guides/setup.md
+++ b/docs/guides/setup.md
@@ -20,8 +20,8 @@ You can download the Video.js source and host it on your own servers, or use the
### CDN Version ###
```html
-
-
+
+
```
@@ -43,8 +43,8 @@ To entirely self-host, you'll need to pull in the font files and let Video.js kn
should Just Workâ˘, but the paths can easily be changed by editing the LESS file and re-building, or by modifying the generated CSS file.
```html
-
-
+
+
diff --git a/docs/guides/skins.md b/docs/guides/skins.md
index c732f223c..0e1d1618d 100644
--- a/docs/guides/skins.md
+++ b/docs/guides/skins.md
@@ -1,28 +1,29 @@
Skins
=====
-The default Video.js skin is made using HTML and CSS, so there's no need to learn a complicated skinning language to update colors or even create an entirely new skin.
+The base Video.js skin is made using HTML and CSS (although we use the [Sass preprocessor](http://sass-lang.com)), and by default these styles are added to the dom for you! That means you can build a custom skin by simply taking advantage of the cascading aspect of CSS and overriding
+the styles you'd like to change.
+
+If you don't want Video.js to inject the base styles for you, you can disable it by setting `window.VIDEOJS_NO_BASE_THEME = false` before Video.js is loaded. Keep in mind that without these base styles
+enabled, you'll need to manually include them.
## Icons
-New in version 4.0 is the use of font icons. All of the icons (play, pause, etc.) use the new custom font, which allows the icons to be scaled and colored just like any other text font.
-
-All of the icons are available as variables in the [LESS](https://github.com/videojs/video.js/blob/master/src/css/video-js.less#L87-L99) source, making it easy to replace icons (such as the loading spinner). The easiest way to try this out is by using the [player skin designer](http://designer.videojs.com/).
-
-
+You can view all of the icons available in the base theme by renaming and viewing [`icons.html.example`](../../sandbox/icons.html.example) in the sandbox directory.
## Customization
-When you create a new skin, you can either override styles in the default skin:
+When you create a new skin, the easiest way to get started is to simply override the base Video.js theme. You should include a new class matching the
+name of your theme, then just start overriding!
```css
-.vjs-default-skin .vjs-play-progress { background: #900; }
+.vjs-skin-hotdog-stand { color: #FF0000; }
+.vjs-skin-hotdog-stand .vjs-control-bar { background: #FFFF00; }
+.vjs-skin-hotdog-stand .vjs-play-progress { background: #FF0000; }
```
-Or remove the 'vjs-default-skin' class from the video tag and create a new skin from scratch.
-
-```html
-
-```
+This would take care of the major areas of the skin (play progress, the control bar background, and icon colors), but you can skin any other aspect.
+Our suggestion is to use a browser such as Firefox and Chrome, and use the developer tools to inspect the different elements and see what you'd like to change and what classes
+to target when you do so.
More custom skins will be available for download soon. If you have one you like you can share it by forking [this example on CodePen.io](http://codepen.io/heff/pen/EarCt), and adding a link on the [Skins wiki page](https://github.com/videojs/video.js/wiki/Skins).
diff --git a/package.json b/package.json
index d6aef59f4..0665c29a1 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "video.js",
"description": "An HTML5 and Flash video player with a common API and skin for both.",
- "version": "4.12.5",
+ "version": "5.0.0-1",
"copyright": "Copyright Brightcove, Inc. ",
"license": "Apache-2.0",
"keywords": [
@@ -20,20 +20,25 @@
"type": "git",
"url": "https://github.com/videojs/video.js.git"
},
- "main": "src/js/video.js",
+ "main": "./dist/video.js",
+ "style": "./dist/video-js.css",
"dependencies": {
+ "global": "^4.3.0",
+ "safe-json-parse": "^4.0.0",
+ "inherits": "^2.0.1",
"videojs-swf": "4.5.4",
- "vtt.js": "git+https://github.com/gkatsev/vtt.js.git#shim-build",
- "global": "^4.3.0"
+ "vtt.js": "git+https://github.com/gkatsev/vtt.js.git#shim-build"
},
"devDependencies": {
"babelify": "^6.0.1",
"blanket": "^1.1.6",
+ "browserify-derequire": "^0.9.4",
"browserify-istanbul": "^0.2.1",
"browserify-versionify": "^1.0.4",
"chg": "~0.2.0",
"grunt": "^0.4.4",
"grunt-aws-s3": "^0.12.1",
+ "grunt-banner": "^0.3.1",
"grunt-browserify": "^3.5.0",
"grunt-cli": "~0.1.0",
"grunt-contrib-clean": "~0.4.0a",
@@ -50,6 +55,7 @@
"grunt-fastly": "^0.1.3",
"grunt-github-releaser": "^0.1.17",
"grunt-karma": "^0.8.3",
+ "grunt-sass": "^0.18.1",
"grunt-version": "~0.3.0",
"grunt-videojs-languages": "0.0.4",
"grunt-zip": "0.10.2",
diff --git a/sandbox/icons.html.example b/sandbox/icons.html.example
new file mode 100644
index 000000000..277d9b38e
--- /dev/null
+++ b/sandbox/icons.html.example
@@ -0,0 +1,38 @@
+
+
+
+
+ Video.js Icons Sandbox
+
+
+
+
+
+
+ Video.js Icons
+ This is a list of all of the icons available in the Video.js base stylesheet. The appropriate class is to the right of each icon.
+
+
+ .vjs-icon-play
+ .vjs-icon-pause
+ .vjs-icon-volume-mute
+ .vjs-icon-volume-low
+ .vjs-icon-volume-mid
+ .vjs-icon-volume-high
+ .vjs-icon-fullscreen-enter
+ .vjs-icon-fullscreen-exit
+ .vjs-icon-square
+ .vjs-icon-spinner
+ .vjs-icon-subtitles
+ .vjs-icon-captions
+ .vjs-icon-chapters
+ .vjs-icon-share
+ .vjs-icon-cog
+ .vjs-icon-circle
+ .vjs-icon-circle-outline
+ .vjs-icon-circle-inner-circle
+
+
+
diff --git a/sandbox/index.html.example b/sandbox/index.html.example
index ec3583c2e..b69e90b1b 100644
--- a/sandbox/index.html.example
+++ b/sandbox/index.html.example
@@ -6,12 +6,11 @@
-
diff --git a/src/css/_utilities.scss b/src/css/_utilities.scss
new file mode 100644
index 000000000..69b21321b
--- /dev/null
+++ b/src/css/_utilities.scss
@@ -0,0 +1,95 @@
+@mixin background-color-with-alpha($color, $alpha) {
+ background-color: $color;
+ background-color: rgba($color, $alpha);
+}
+
+@mixin transition($string: $transition--default) {
+ -webkit-transition: $string;
+ -moz-transition: $string;
+ -o-transition: $string;
+ transition: $string;
+}
+
+@mixin hide-visually {
+ border: 0;
+ clip: rect(0 0 0 0);
+ height: 1px;
+ margin: -1px;
+ overflow: hidden;
+ padding: 0;
+ position: absolute;
+ width: 1px;
+}
+
+@mixin border-radius($radius) {
+ -webkit-border-radius: $radius;
+ -moz-border-radius: $radius;
+ border-radius: $radius;
+}
+
+@mixin animation($string: spin 1s infinite linear) {
+ -webkit-animation: $string;
+ -moz-animation: $string;
+ -o-animation: $string;
+ animation: $string;
+}
+
+@mixin display-flex($alignment: '', $justification: '') {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+
+ @if $alignment != '' {
+ -webkit-box-align: $alignment;
+ -webkit-align-items: $alignment;
+ -ms-flex-align: $alignment;
+ align-items: $alignment;
+ }
+
+ @if $justification != '' {
+ -webkit-box-pack: $justification;
+ -webkit-justify-content: $justification;
+ -ms-flex-pack: $justification;
+ justify-content: $justification;
+ }
+}
+
+@mixin flex($value) {
+ // @include context('.video-js', '.video-js.vjs-no-flex') {
+ // display: table-cell;
+ // vertical-align: middle;
+ // @if ($value == 'auto') {
+ // width: auto;
+ // }
+ // }
+
+ -webkit-box-flex: $value;
+ -moz-box-flex: $value;
+ -webkit-flex: $value;
+ -ms-flex: $value;
+ flex: $value;
+}
+
+// https://developer.mozilla.org/en-US/docs/Web/CSS/user-select
+@mixin user-select($string: none) {
+ -webkit-user-select: $string;
+ -moz-user-select: $string;
+ -ms-user-select: $string;
+ user-select: $string
+}
+
+// https://developer.mozilla.org/en-US/docs/Web/CSS/box-shadow
+@mixin box-shadow ($string: 0 0 1em rgba(0, 0, 0, 0.25)) {
+ -webkit-box-shadow: $string;
+ -moz-box-shadow: $string;
+ box-shadow: $string;
+}
+
+@mixin order($value) {
+ -webkit-box-ordinal-group: $value;
+ -moz-box-ordinal-group: $value;
+ -ms-flex-order: $value;
+ -webkit-order: $value;
+ order: $value;
+}
diff --git a/src/css/_variables.scss b/src/css/_variables.scss
new file mode 100644
index 000000000..8267ed0e3
--- /dev/null
+++ b/src/css/_variables.scss
@@ -0,0 +1,12 @@
+$primary-text: #fff;
+$secondary-text: #F4A460; // currently just used for visited links in errors and such.
+
+$primary-bg: #000;
+$secondary-bg: lighten($primary-bg, 35%);
+
+$icon-font-family: 'VideoJS';
+$text-font-family: Arial, sans-serif;
+$base-font-size: 10px;
+
+$control-bar-bg: #2B333F;
+$control-bar-transparency: 0.5;
diff --git a/src/css/components/_adaptive.scss b/src/css/components/_adaptive.scss
new file mode 100644
index 000000000..d8c01d805
--- /dev/null
+++ b/src/css/components/_adaptive.scss
@@ -0,0 +1,37 @@
+// When the player is absurdly tiny, display nothing but:
+// - Play button
+// - Fullscreen Button
+.video-js.vjs-layout-tiny:not(.vjs-fullscreen) {
+ .vjs-custom-control-spacer { @include flex(auto); }
+ &.vjs-no-flex .vjs-custom-control-spacer { width: auto; }
+
+ .vjs-current-time, .vjs-captions-button, .vjs-time-divider,
+ .vjs-progress-control, .vjs-duration, .vjs-remaining-time, .vjs-playback-rate,
+ .vjs-mute-control, .vjs-volume-control, .vjs-chapters-button, .vjs-captions-button,
+ .vjs-subtitles-button, .vjs-volume-menu-button { display: none; }
+}
+
+// When the player is x-small, display nothing but:
+// - Play button
+// - Progress bar
+// - Fullscreen Button
+.video-js.vjs-layout-x-small:not(.vjs-fullscreen) {
+ .vjs-current-time, .vjs-captions-button, .vjs-time-divider,
+ .vjs-duration, .vjs-remaining-time, .vjs-playback-rate, .vjs-captions-button,
+ .vjs-mute-control, .vjs-volume-control, .vjs-chapters-button,
+ .vjs-subtitles-button, .vjs-volume-button, .vjs-fullscreen-control { display: none; }
+}
+
+
+// When the player is small, display nothing but:
+// - Play button
+// - Progress bar
+// - Volume menu button
+// - Captions Button
+// - Fullscreen button
+.video-js.vjs-layout-small:not(.vjs-fullscreen) {
+ .vjs-current-time, .vjs-captions-button, .vjs-time-divider,
+ .vjs-duration, .vjs-remaining-time, .vjs-playback-rate,
+ .vjs-mute-control, .vjs-volume-control, .vjs-chapters-button,
+ .vjs-subtitles-button { display: none; }
+}
diff --git a/src/css/components/_big-play.scss b/src/css/components/_big-play.scss
new file mode 100644
index 000000000..28d6b4068
--- /dev/null
+++ b/src/css/components/_big-play.scss
@@ -0,0 +1,40 @@
+.video-js .vjs-big-play-button {
+ font-size: 3em;
+ line-height: 1em;
+ display: block;
+ z-index: 2;
+ position: absolute;
+ top: 10px;
+ left: 10px;
+ padding: 0.2em 1em;
+ cursor: pointer;
+ opacity: 1;
+ border: 2px solid $primary-text;
+
+ /* Need a slightly gray bg so it can be seen on black backgrounds *///
+ @include background-color-with-alpha($primary-bg, 0.8);
+ @include border-radius(0.3em);
+ @include transition(all 0.4s);
+
+ @extend .vjs-icon-play;
+}
+
+/* Hide if controls are disabled, the video is playing, or native controls are used. */
+.video-js.vjs-controls-disabled .vjs-big-play-button,
+.video-js.vjs-has-started .vjs-big-play-button,
+.video-js.vjs-using-native-controls .vjs-big-play-button {
+ display: none;
+}
+
+.video-js:hover .vjs-big-play-button,
+.video-js .vjs-big-play-button:focus {
+ outline: 0;
+ border-color: $primary-text;
+
+ @include background-color-with-alpha($secondary-bg, 0.75);
+ @include transition(all 0s);
+}
+
+.vjs-error .vjs-big-play-button {
+ display: none;
+}
diff --git a/src/css/components/_captions.scss b/src/css/components/_captions.scss
new file mode 100644
index 000000000..df8db5dbe
--- /dev/null
+++ b/src/css/components/_captions.scss
@@ -0,0 +1,3 @@
+.video-js .vjs-captions-button {
+ @extend .vjs-icon-captions;
+}
diff --git a/src/css/components/_chapters.scss b/src/css/components/_chapters.scss
new file mode 100644
index 000000000..85beba5d7
--- /dev/null
+++ b/src/css/components/_chapters.scss
@@ -0,0 +1,12 @@
+.video-js .vjs-chapters-button {
+ @extend .vjs-icon-chapters;
+}
+
+.video-js .vjs-chapters-button.vjs-menu-button .vjs-menu {
+ left: 2em;
+}
+
+.video-js .vjs-chapters-button.vjs-menu-button .vjs-menu .vjs-menu-content {
+ width: 24em;
+ left: -12em;
+}
diff --git a/src/css/components/_control-bar.scss b/src/css/components/_control-bar.scss
new file mode 100644
index 000000000..7c3386c51
--- /dev/null
+++ b/src/css/components/_control-bar.scss
@@ -0,0 +1,57 @@
+.video-js .vjs-control-bar {
+ display: none;
+ width: 100%;
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ height: 3.0em;
+
+ @include background-color-with-alpha($control-bar-bg, $control-bar-transparency);
+}
+
+// Video has started playing
+.video-js.vjs-has-started .vjs-control-bar {
+ @include display-flex;
+ visibility: visible;
+ opacity: 1;
+
+ $trans: visibility 0.1s, opacity 0.1s; // Var needed because of comma
+ @include transition($trans);
+}
+
+// Video has started playing AND user is inactive
+.video-js.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar {
+ visibility: hidden;
+ opacity: 0;
+
+ $trans: visibility 1.0s, opacity 1.0s;
+ @include transition($trans);
+}
+
+.video-js.vjs-controls-disabled .vjs-control-bar,
+.video-js.vjs-using-native-controls .vjs-control-bar,
+.video-js.vjs-error .vjs-control-bar {
+ display: none;
+}
+
+// Don't hide the control bar if it's audio
+.video-js.vjs-audio.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar {
+ opacity: 1;
+ visibility: visible;
+}
+
+/* IE8 is flakey with fonts, and you have to change the actual content to force
+fonts to show/hide properly.
+- "\9" IE8 hack didn't work for this
+- Found in XP IE8 from http://modern.ie. Does not show up in "IE8 mode" in IE9
+*/
+$ie8screen: "\0screen";
+.video-js.vjs-user-inactive.vjs-playing .vjs-control-bar :before {
+ @media #{$ie8screen} { content: ""; }
+}
+
+/* IE 8 + 9 Support */
+.video-js.vjs-has-started.vjs-no-flex .vjs-control-bar {
+ display: table;
+}
diff --git a/src/css/components/_control.scss b/src/css/components/_control.scss
new file mode 100644
index 000000000..1094d1e05
--- /dev/null
+++ b/src/css/components/_control.scss
@@ -0,0 +1,39 @@
+.video-js .vjs-control {
+ outline: none;
+ position: relative;
+ text-align: center;
+ margin: 0;
+ padding: 0;
+ height: 100%;
+ width: 4em;
+ @include flex(none);
+}
+
+.video-js .vjs-control:before {
+ font-size: 1.8em;
+ line-height: 1.67;
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ text-align: center;
+}
+
+/* Replacement for focus outline */
+.video-js .vjs-control:focus:before,
+.video-js .vjs-control:hover:before,
+.video-js .vjs-control:focus {
+ text-shadow: 0em 0em 1em rgba($primary-text, 1);
+}
+
+/* Hide control text visually, but have it available for screenreaders */
+.video-js .vjs-control-text {
+ @include hide-visually;
+}
+
+/* IE 8 + 9 Support */
+.vjs-no-flex .vjs-control {
+ display: table-cell;
+ vertical-align: middle;
+}
diff --git a/src/css/components/_error.scss b/src/css/components/_error.scss
new file mode 100644
index 000000000..b8acd7014
--- /dev/null
+++ b/src/css/components/_error.scss
@@ -0,0 +1,47 @@
+.vjs-error-display {
+ display: none;
+}
+
+.vjs-error .vjs-error-display {
+ display: block;
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+}
+
+.vjs-error .vjs-error-display:before {
+ content: 'X';
+ font-family: $text-font-family;
+ font-size: 4em;
+ color: $secondary-bg;
+ /* In order to center the play icon vertically we need to set the line height
+ to the same as the button height */
+ line-height: 1;
+ text-shadow: 0.05em 0.05em 0.1em $primary-bg;
+ text-align: center /* Needed for IE8 */;
+ vertical-align: middle;
+
+ position: absolute;
+ left: 0;
+ top: 50%;
+ margin-top: -0.5em;
+ width: 100%;
+}
+
+.vjs-error-display div {
+ position: absolute;
+ bottom: 1em;
+ right: 0;
+ left: 0;
+ font-size: 1.4em;
+ text-align: center;
+ padding: 3px;
+
+ @include background-color-with-alpha($primary-bg, 0.5);
+}
+
+.vjs-error-display a, .vjs-error-display a:visited {
+ color: $secondary-text;
+}
diff --git a/src/css/components/_fullscreen.scss b/src/css/components/_fullscreen.scss
new file mode 100644
index 000000000..c36a9c00c
--- /dev/null
+++ b/src/css/components/_fullscreen.scss
@@ -0,0 +1,12 @@
+.video-js .vjs-fullscreen-control {
+ width: 3.8em;
+ cursor: pointer;
+ @include flex(none);
+}
+.video-js .vjs-fullscreen-control {
+ @extend .vjs-icon-fullscreen-enter;
+}
+/* Switch to the exit icon when the player is in fullscreen */
+.video-js.vjs-fullscreen .vjs-fullscreen-control {
+ @extend .vjs-icon-fullscreen-exit;
+}
diff --git a/src/css/components/_icons.scss b/src/css/components/_icons.scss
new file mode 100644
index 000000000..88cfa134b
--- /dev/null
+++ b/src/css/components/_icons.scss
@@ -0,0 +1,79 @@
+@font-face {
+ font-family: $icon-font-family;
+ src: url('font/VideoJS.eot');
+}
+@font-face {
+ font-family: $icon-font-family;
+ src: url(data:application/x-font-ttf;charset=utf-8;base64,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) format('truetype'),
+ url(data:application/font-woff;charset=utf-8;base64,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) format('woff');
+ font-weight: normal;
+ font-style: normal;
+}
+
+// http://sass-lang.com/documentation/file.SASS_REFERENCE.html#maps
+$icons: (
+ play: "\25b6",
+ pause: "\e830",
+ volume-mute: "\e84b",
+ volume-low: "\e84a",
+ volume-mid: "\e849",
+ volume-high: "\e84c",
+ fullscreen-enter: "\e64b",
+ fullscreen-exit: "\e64c",
+ square: "\e601",
+ spinner: "\e650",
+ subtitles: "\e80d",
+ captions: "\e81e",
+ chapters: "\e891",
+ share: "\e61a",
+ cog: "\e8b1",
+ circle: "\e692",
+ circle-outline: "\e6f2",
+ circle-inner-circle: "\e603"
+);
+
+// NOTE: This is as complex as we want to get with SCSS functionality.
+//
+// Now that we have a map of icons above, we can iterate over that map and create an icon class
+// for each icon in that list. The iterator below produces CSS classes like this:
+//
+// .vjs-icon-play {
+// font-family: VideoJS;
+// font-weight: normal;
+// font-style: normal;
+// }
+// .vjs-icon-play:before { content: "\25b6"; }
+//
+// We can then use @extend in the codebase when we need to add an icon to a class. @extend builds up
+// the selectors for you so you can avoid duplication. This is generally a bad idea, but since each
+// icon should only be extended one or two other places, we'll roll with it.
+@each $name, $content in $icons {
+ .vjs-icon-#{$name} {
+ font-family: $icon-font-family;
+ font-weight: normal;
+ font-style: normal;
+
+ &:before {
+ content: $content;
+ }
+ }
+}
+
+// $icon-play: "\25b6";
+// $icon-pause: "\e830";
+// $icon-volume-mute: "\e84b";
+// $icon-volume-low: "\e84a";
+// $icon-volume-mid: "\e849";
+// $icon-volume-high: "\e84c";
+// $icon-fullscreen-enter: "\e64b";
+// $icon-fullscreen-exit: "\e64c";
+// $icon-square: "\e009";
+// $icon-spinner: "\e650";
+// $icon-subtitles: "\e80d";
+// $icon-captions: "\e81e";
+// $icon-chapters: "\e891";
+// $icon-share: "\e61a";
+// $icon-cog: "\e8b1";
+// $icon-circle: "\e692";
+// $icon-circle-outline: "\e6f2";
+// $icon-circle-inner-circle: "\e603";
diff --git a/src/css/components/_layout.scss b/src/css/components/_layout.scss
new file mode 100644
index 000000000..371bead21
--- /dev/null
+++ b/src/css/components/_layout.scss
@@ -0,0 +1,101 @@
+.video-js {
+ display: block;
+ box-sizing: border-box;
+
+ color: $primary-text;
+ background-color: $primary-bg;
+ position: relative;
+ padding: 0;
+ /* Start with 10px for base font size so other dimensions can be em based and
+ easily calculable. */
+ font-size: $base-font-size;
+ /* Allow poster to be vertially aligned. */
+ vertical-align: middle;
+
+ /* Provide some basic defaults for fonts */
+ font-weight: normal;
+ font-style: normal;
+ /* Avoiding helvetica: issue #376 */
+ font-family: $text-font-family;
+
+ @include user-select(none);
+
+ /* Fix for Firefox 9 fullscreen (only if it is enabled). Not needed when
+ checking fullScreenEnabled. */
+ &:-moz-full-screen { position: absolute; }
+
+ &:-webkit-full-screen {
+ width: 100% !important;
+ height: 100% !important;
+ }
+}
+
+/* All elements inherit border-box sizing */
+.video-js *,
+.video-js *:before,
+.video-js *:after {
+ box-sizing: inherit;
+}
+
+/* Playback technology elements expand to the width/height of the containing div
+ or */
+.video-js .vjs-tech {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+}
+
+/* Fullscreen Styles */
+body.vjs-full-window {
+ padding: 0;
+ margin: 0;
+ height: 100%;
+ /* Fix for IE6 full-window. http://www.cssplay.co.uk/layouts/fixed.html */
+ overflow-y: auto;
+}
+.video-js.vjs-fullscreen {
+ position: fixed;
+ overflow: hidden;
+ z-index: 1000;
+ left: 0;
+ top: 0;
+ bottom: 0;
+ right: 0;
+ width: 100% !important;
+ height: 100% !important;
+}
+.video-js.vjs-fullscreen.vjs-user-inactive {
+ cursor: none;
+}
+
+
+/* Hide disabled or unsupported controls. */
+.vjs-hidden { display: none !important; }
+
+.vjs-lock-showing {
+ display: block !important;
+ opacity: 1;
+ visibility: visible;
+}
+
+/* In IE8 w/ no JavaScript (no HTML5 shim), the video tag doesn't register.
+The .video-js classname on the video tag also isn't considered.
+This optional paragraph inside the video tag can provide a message to users
+about what's required to play video. */
+.vjs-no-js {
+ padding: 20px;
+ color: $primary-text;
+ background-color: $primary-bg;
+ font-size: 18px;
+ font-family: $text-font-family;
+ text-align: center;
+ width: 300px;
+ height: 150px;
+ margin: 0px auto;
+}
+
+.vjs-no-js a, .vjs-no-js a:visited {
+ color: $secondary-text;
+}
diff --git a/src/css/components/_live.scss b/src/css/components/_live.scss
new file mode 100644
index 000000000..abd07acea
--- /dev/null
+++ b/src/css/components/_live.scss
@@ -0,0 +1,11 @@
+.video-js.vjs-live .vjs-time-control,
+.video-js.vjs-live .vjs-time-divider,
+.video-js.vjs-live .vjs-progress-control {
+ display: none;
+}
+
+.video-js .vjs-live-control {
+ display: none;
+ font-size: 1em;
+ line-height: 3em;
+}
diff --git a/src/css/components/_loading.scss b/src/css/components/_loading.scss
new file mode 100644
index 000000000..792193649
--- /dev/null
+++ b/src/css/components/_loading.scss
@@ -0,0 +1,64 @@
+.vjs-loading-spinner {
+ display: none;
+
+ position: absolute;
+ top: 50%;
+ left: 50%;
+
+ font-size: 4em;
+ line-height: 1;
+
+ width: 1em;
+ height: 1em;
+
+ margin-left: -0.5em;
+ margin-top: -0.5em;
+
+ opacity: 0.75;
+
+ @extend .vjs-icon-spinner;
+}
+
+/* Show the spinner when waiting for data and seeking to a new time */
+.vjs-waiting .vjs-loading-spinner,
+.vjs-seeking .vjs-loading-spinner {
+ display: block;
+
+ /* only animate when showing because it can be processor heavy *///
+ @include animation(spin 1.5s infinite linear);
+}
+
+/* Errors are unrecoverable without user interaction so hide the spinner */
+.vjs-error .vjs-loading-spinner {
+ display: none;
+
+ /* ensure animation doesn't continue while hidden *///
+ @include animation(none);
+}
+
+.video-js .vjs-loading-spinner:before {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 1em;
+ height: 1em;
+ text-align: center;
+ text-shadow: 0em 0em 0.1em $primary-bg;
+}
+
+@-moz-keyframes spin {
+ 0% { -moz-transform: rotate(0deg); }
+ 100% { -moz-transform: rotate(359deg); }
+}
+@-webkit-keyframes spin {
+ 0% { -webkit-transform: rotate(0deg); }
+ 100% { -webkit-transform: rotate(359deg); }
+}
+@-o-keyframes spin {
+ 0% { -o-transform: rotate(0deg); }
+ 100% { -o-transform: rotate(359deg); }
+}
+@keyframes spin {
+ 0% { transform: rotate(0deg); }
+ 100% { transform: rotate(359deg); }
+}
diff --git a/src/css/components/_menu.scss b/src/css/components/_menu.scss
new file mode 100644
index 000000000..273ab90fb
--- /dev/null
+++ b/src/css/components/_menu.scss
@@ -0,0 +1,69 @@
+.video-js .vjs-menu-button {
+ cursor: pointer;
+}
+
+.video-js .vjs-menu {
+ display: none;
+ position: absolute;
+ bottom: 0;
+ left: -3em; /* (Width of vjs-menu - width of button) / 2 */
+ width: 0em;
+ height: 0em;
+ margin-bottom: 1.5em;
+ border-top-color: rgba(7, 40, 50, $control-bar-transparency); /* Same as ul background */
+}
+
+/* Button Pop-up Menu */
+.video-js .vjs-menu-content {
+ @include background-color-with-alpha($primary-bg, 0.7);
+}
+
+.video-js .vjs-menu-button .vjs-menu .vjs-menu-content {
+ display: block;
+ padding: 0; margin: 0;
+ position: absolute;
+ width: 10em;
+ bottom: 1.5em; /* Same bottom as vjs-menu border-top */
+ max-height: 15em;
+ overflow: auto;
+}
+
+.video-js .vjs-menu-button:hover .vjs-control-content .vjs-menu,
+.video-js .vjs-control-content .vjs-menu.vjs-lock-showing {
+ display: block;
+}
+/* prevent menus from opening while scrubbing (FF, IE) */
+.video-js.vjs-scrubbing .vjs-menu-button:hover .vjs-control-content .vjs-menu {
+ display: none;
+}
+.video-js .vjs-menu-button ul li {
+ list-style: none;
+ margin: 0;
+ padding: 0.2em 0;
+ line-height: 1.4em;
+ font-size: 1.2em;
+ text-align: center;
+ text-transform: lowercase;
+}
+.video-js .vjs-menu-button ul li.vjs-selected {
+ background-color: $primary-bg;
+}
+.video-js .vjs-menu-button ul li:focus,
+.video-js .vjs-menu-button ul li:hover,
+.video-js .vjs-menu-button ul li.vjs-selected:focus,
+.video-js .vjs-menu-button ul li.vjs-selected:hover {
+ outline: 0;
+ color: $primary-bg;
+
+ @include background-color-with-alpha($primary-text, 0.75);
+}
+.video-js .vjs-menu-button ul li.vjs-menu-title {
+ text-align: center;
+ text-transform: uppercase;
+ font-size: 1em;
+ line-height: 2em;
+ padding: 0;
+ margin: 0 0 0.3em 0;
+ font-weight: bold;
+ cursor: default;
+}
diff --git a/src/css/components/_play-pause.scss b/src/css/components/_play-pause.scss
new file mode 100644
index 000000000..b2c09c9e7
--- /dev/null
+++ b/src/css/components/_play-pause.scss
@@ -0,0 +1,11 @@
+.video-js .vjs-play-control {
+ width: 5em;
+ cursor: pointer;
+ @include flex(none);
+}
+.video-js .vjs-play-control {
+ @extend .vjs-icon-play;
+}
+.video-js.vjs-playing .vjs-play-control {
+ @extend .vjs-icon-pause;
+}
diff --git a/src/css/components/_playback-rate.scss b/src/css/components/_playback-rate.scss
new file mode 100644
index 000000000..1591f0183
--- /dev/null
+++ b/src/css/components/_playback-rate.scss
@@ -0,0 +1,20 @@
+// TODO: I feel like this should be a generic menu. Research later.
+.video-js .vjs-playback-rate .vjs-playback-rate-value {
+ font-size: 1.5em;
+ line-height: 2;
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ text-align: center;
+}
+
+.video-js .vjs-playback-rate .vjs-menu {
+ left: 0em;
+}
+.video-js .vjs-playback-rate.vjs-menu-button .vjs-menu .vjs-menu-content {
+ width: 4em;
+ left: 0;
+ list-style: none;
+}
diff --git a/src/css/components/_poster.scss b/src/css/components/_poster.scss
new file mode 100644
index 000000000..f612cc88b
--- /dev/null
+++ b/src/css/components/_poster.scss
@@ -0,0 +1,41 @@
+.vjs-poster {
+ background-repeat: no-repeat;
+ background-position: 50% 50%;
+ background-size: contain;
+ cursor: pointer;
+ margin: 0;
+ padding: 0;
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+}
+.vjs-poster img {
+ display: block;
+ margin: 0 auto;
+ max-height: 100%;
+ padding: 0;
+ width: 100%;
+}
+
+/* Hide the poster after the video has started playing */
+.video-js.vjs-has-started .vjs-poster {
+ display: none;
+}
+
+/* Don't hide the poster if we're playing audio */
+.video-js.vjs-audio.vjs-has-started .vjs-poster {
+ display: block;
+}
+
+/* Hide the poster when controls are disabled because it's clickable
+and the native poster can take over */
+.video-js.vjs-controls-disabled .vjs-poster {
+ display: none;
+}
+
+/* Hide the poster when native controls are used otherwise it covers them */
+.video-js.vjs-using-native-controls .vjs-poster {
+ display: none;
+}
diff --git a/src/css/components/_progress.scss b/src/css/components/_progress.scss
new file mode 100644
index 000000000..f9315cb0d
--- /dev/null
+++ b/src/css/components/_progress.scss
@@ -0,0 +1,50 @@
+.video-js .vjs-progress-control {
+ @include flex(auto);
+ @include display-flex(center);
+}
+
+/* Box containing play and load progresses. Also acts as seek scrubber. */
+.video-js .vjs-progress-holder {
+ @include flex(auto);
+ height: 0.3em;
+}
+
+/* Progress Bars */
+.video-js .vjs-progress-holder .vjs-play-progress,
+.video-js .vjs-progress-holder .vjs-load-progress,
+.video-js .vjs-progress-holder .vjs-load-progress div {
+ position: absolute;
+ display: block;
+ height: 100%;
+ margin: 0;
+ padding: 0;
+ /* updated by javascript during playback */
+ width: 0;
+ /* Needed for IE6 *///
+ left: 0;
+ top: 0;
+}
+
+.video-js .vjs-play-progress {
+ background-color: $primary-text;
+}
+.video-js .vjs-load-progress {
+ background: rgb(100, 100, 100) /* IE8- Fallback */;
+ background: rgba(255, 255, 255, 0.2);
+}
+
+/* there are child elements of the load progress bar that represent the
+specific time ranges that have been buffered */
+.video-js .vjs-load-progress div {
+ background: rgba($secondary-bg, 0.1);
+}
+
+.video-js .vjs-slider-handle.vjs-seek-handle {
+ width: 0.95em;
+ height: 0.95em;
+}
+
+
+.video-js.vjs-no-flex .vjs-progress-control {
+ width: auto;
+}
diff --git a/src/css/components/_slider.scss b/src/css/components/_slider.scss
new file mode 100644
index 000000000..7f6f4bf8a
--- /dev/null
+++ b/src/css/components/_slider.scss
@@ -0,0 +1,39 @@
+.video-js .vjs-slider {
+ outline: 0;
+ position: relative;
+ cursor: pointer;
+ padding: 0;
+
+ @include background-color-with-alpha($secondary-bg, 0.9);
+}
+
+.video-js .vjs-slider:focus {
+ text-shadow: 0em 0em 1em rgba($primary-text, 1);
+
+ @include box-shadow(0 0 1em $primary-text);
+}
+
+.video-js .vjs-slider-handle {
+ position: absolute;
+ @extend .vjs-icon-circle;
+}
+
+.video-js .vjs-slider-horizontal .vjs-slider-handle {
+ left: 0;
+ top: -0.34em;
+}
+
+.video-js .vjs-slider-vertical .vjs-slider-handle {
+ left: -0.3em;
+ bottom: 0;
+}
+
+.video-js .vjs-slider-handle:before {
+ font-size: 1em;
+ line-height: 1;
+ text-align: center;
+
+ position: absolute;
+ top: 0;
+ left: 0;
+}
diff --git a/src/css/components/_subtitles.scss b/src/css/components/_subtitles.scss
new file mode 100644
index 000000000..3527c7a5d
--- /dev/null
+++ b/src/css/components/_subtitles.scss
@@ -0,0 +1,3 @@
+.video-js .vjs-subtitles-button {
+ @extend .vjs-icon-subtitles;
+}
diff --git a/src/css/components/_text-track.scss b/src/css/components/_text-track.scss
new file mode 100644
index 000000000..c2909a425
--- /dev/null
+++ b/src/css/components/_text-track.scss
@@ -0,0 +1,26 @@
+.video-js .vjs-text-track-display {
+ text-align: center;
+ position: absolute;
+ bottom: 4em;
+ /* Leave padding on left and right */
+ left: 1em;
+ right: 1em;
+}
+
+/* Move captions down when controls aren't being shown */
+.video-js.vjs-user-inactive.vjs-playing .vjs-text-track-display {
+ bottom: 1em;
+}
+
+/* Individual tracks */
+.video-js .vjs-text-track {
+ font-size: 1.4em;
+ text-align: center;
+ margin-bottom: 0.1em;
+ /* Transparent black background, or fallback to all black (oldIE) */
+ @include background-color-with-alpha($primary-bg, 0.5);
+}
+
+.video-js .vjs-subtitles { color: #fff /* Subtitles are white */; }
+.video-js .vjs-captions { color: #fc6 /* Captions are yellow */; }
+.vjs-tt-cue { display: block; }
diff --git a/src/css/components/_time.scss b/src/css/components/_time.scss
new file mode 100644
index 000000000..7710b8691
--- /dev/null
+++ b/src/css/components/_time.scss
@@ -0,0 +1,11 @@
+.video-js .vjs-time-control {
+ @include flex(none);
+ font-size: 1em;
+ line-height: 3em;
+}
+
+/* We need the extra specificity that referencing .vjs-no-flex provides. */
+.video-js .vjs-current-time, .video-js.vjs-no-flex .vjs-current-time { display: none; }
+.video-js .vjs-duration, .video-js.vjs-no-flex .vjs-duration { display: none; }
+.video-js .vjs-remaining-time, .video-js.vjs-no-flex .vjs-remaining-time { display: none; }
+.vjs-time-divider { display: none; line-height: 3em; }
diff --git a/src/css/components/_volume.scss b/src/css/components/_volume.scss
new file mode 100644
index 000000000..25ea6b242
--- /dev/null
+++ b/src/css/components/_volume.scss
@@ -0,0 +1,104 @@
+.video-js .vjs-mute-control,
+.video-js .vjs-volume-menu-button {
+ cursor: pointer;
+ @include flex(none);
+ @extend .vjs-icon-volume-high;
+}
+
+.video-js .vjs-mute-control.vjs-vol-0,
+.video-js .vjs-volume-menu-button.vjs-vol-0 {
+ @extend .vjs-icon-volume-mute;
+}
+.video-js .vjs-mute-control.vjs-vol-1,
+.video-js .vjs-volume-menu-button.vjs-vol-1 {
+ @extend .vjs-icon-volume-low;
+}
+.video-js .vjs-mute-control.vjs-vol-2,
+.video-js .vjs-volume-menu-button.vjs-vol-2 {
+ @extend .vjs-icon-volume-mid;
+}
+
+.video-js .vjs-volume-control {
+ width: 5em;
+ @include flex(none);
+ @include display-flex(center);
+}
+
+.video-js .vjs-volume-bar.vjs-slider-horizontal {
+ width: 5em;
+ height: 0.3em;
+}
+
+.video-js .vjs-volume-bar.vjs-slider-vertical {
+ width: 0.3em;
+ height: 5em;
+ margin: 1.3em;
+}
+
+.video-js .vjs-volume-level {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+
+ background-color: $primary-text;
+}
+
+.video-js .vjs-slider-vertical .vjs-volume-level { width: 0.3em; }
+.video-js .vjs-slider-horizontal .vjs-volume-level { height: 0.3em; }
+
+.video-js .vjs-volume-bar .vjs-volume-handle {
+ width: 0.8em;
+ height: 0.8em;
+}
+
+/* Assumes volume starts at 1.0. If you change the size of the
+handle relative to the volume bar, you'll need to update this value
+too. */
+.video-js .vjs-volume-bar.vjs-slider-vertical .vjs-volume-level { height: 100%; }
+.video-js .vjs-volume-bar.vjs-slider-vertical .vjs-volume-handle { bottom: 4.3em; }
+.video-js .vjs-volume-bar.vjs-slider-horizontal .vjs-volume-level { width: 100%; }
+.video-js .vjs-volume-bar.vjs-slider-horizontal .vjs-volume-handle { left: 4.3em; }
+
+.video-js .vjs-volume-handle:before {
+ font-size: 0.9em;
+}
+
+/* The volume menu button is like menu buttons (captions/subtitles) but works
+a little differently. It needs to be possible to tab to the volume slider
+without hitting space bar on the menu button. To do this we're not using
+display:none to hide the slider menu by default, and instead setting the
+width and height to zero. */
+.video-js .vjs-volume-menu-button .vjs-menu {
+ display: block;
+ width: 0;
+ height: 0;
+ left: 0.5em;
+ border-top-color: transparent;
+}
+
+.video-js .vjs-menu-button.vjs-volume-menu-button .vjs-menu .vjs-menu-content {
+ height: 0;
+ width: 0;
+
+ // Avoids unnecessary scrollbars in the menu content. Primarily noticed in Chrome on Linux.
+ overflow-x: hidden;
+ overflow-y: hidden;
+}
+
+.video-js .vjs-volume-menu-button:hover .vjs-menu,
+.video-js .vjs-volume-menu-button .vjs-menu.vjs-lock-showing {
+ // border-top-color: rgba(7, 40, 50, 0.5); /* Same as ul background */
+}
+
+.video-js .vjs-volume-menu-button:hover .vjs-menu .vjs-menu-content,
+.video-js .vjs-volume-menu-button .vjs-menu.vjs-lock-showing .vjs-menu-content {
+ height: 8em;
+ width: 2.9em;
+}
+
+// By default, all menu items are shown, but we hide .vjs-mute-control and .vjs-volume-control
+// so that the volume menu button is the only visible volume control.
+.video-js .vjs-mute-control,
+.video-js .vjs-volume-control {
+ display: none;
+}
diff --git a/src/css/font/VideoJS.eot b/src/css/font/VideoJS.eot
new file mode 100755
index 000000000..5d29e5adf
Binary files /dev/null and b/src/css/font/VideoJS.eot differ
diff --git a/src/css/font/VideoJS.svg b/src/css/font/VideoJS.svg
new file mode 100755
index 000000000..d9a39d7b6
--- /dev/null
+++ b/src/css/font/VideoJS.svg
@@ -0,0 +1,40 @@
+
+
+
+Generated by IcoMoon
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/css/font/VideoJS.ttf b/src/css/font/VideoJS.ttf
new file mode 100755
index 000000000..bf0b443c6
Binary files /dev/null and b/src/css/font/VideoJS.ttf differ
diff --git a/src/css/font/VideoJS.woff b/src/css/font/VideoJS.woff
new file mode 100755
index 000000000..e130b76c5
Binary files /dev/null and b/src/css/font/VideoJS.woff differ
diff --git a/src/css/font/vjs.eot b/src/css/font/vjs.eot
deleted file mode 100755
index a2c0f5f24..000000000
Binary files a/src/css/font/vjs.eot and /dev/null differ
diff --git a/src/css/font/vjs.svg b/src/css/font/vjs.svg
deleted file mode 100755
index fa6aa7b5f..000000000
--- a/src/css/font/vjs.svg
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
-Generated by IcoMoon
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/css/font/vjs.ttf b/src/css/font/vjs.ttf
deleted file mode 100755
index 682a9b21e..000000000
Binary files a/src/css/font/vjs.ttf and /dev/null differ
diff --git a/src/css/font/vjs.woff b/src/css/font/vjs.woff
deleted file mode 100644
index a79d0fa09..000000000
Binary files a/src/css/font/vjs.woff and /dev/null differ
diff --git a/src/css/video-js.less b/src/css/video-js.less
deleted file mode 100644
index 9a06afb91..000000000
--- a/src/css/video-js.less
+++ /dev/null
@@ -1,1237 +0,0 @@
- /*!
-Video.js Default Styles (http://videojs.com)
-@version GENERATED_AT_BUILD
-Create your own skin at http://designer.videojs.com
-*/
-
-// To customize the player skin, change the values of the variables or edit the
-// CSS below.
-// (This file uses LESS. Learn more at http://lesscss.org/)
-
-// The base font size controls the size of everything, not just text. All
-// dimensions use em-based sizes so that the scale along with the font size.
-// Try increasing it to 20px and see what happens.
-@base-font-size: 10px;
-@touch-device-font-size: 15px;
-
-// The main font color controls the color of the text and the icons (font icons)
-@main-font-color: #CCCCCC; // e.g. rgb(255, 255, 255) or #ffffff
-
-// The default color of control backgrounds is mostly black but with a little
-// bit of blue so it can still be seen on all black video frames, which are
-// common.
-@control-bg-color: #07141E; // e.g. rgb(255, 255, 255) or #ffffff
-@control-bg-alpha: 0.7; // 1.0 = 100% opacity, 0.0 = 0% opacity
-
-// The slider bar color is used for the progress bar and the volume bar
-@slider-bar-color: #66A8CC; // e.g. rgb(255, 255, 255) or #ffffff
-// The background of the progress bar and volume bar have a lined pattern that
-// is created from a base64 encoded image. You can generate your own pattern at
-// http://www.patternify.com/ then replace the value in the quotes with your own
-@slider-bar-pattern: ~'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAGCAYAAADgzO9IAAAAP0lEQVQIHWWMAQoAIAgDR/QJ/Ub//04+w7ZICBwcOg5FZi5iBB82AGzixEglJrd4TVK5XUJpskSTEvpdFzX9AB2pGziSQcvAAAAAAElFTkSuQmCC';
-// The color of the slider background
-@slider-background-color: #333333;
-@slider-background-alpha: 0.9; // 1.0 = 100% opacity, 0.0 = 0% opacity
-
-// The "Big Play Button" is the play button that shows before the video plays.
-// To center it set the align values to center and middle. The typical location
-// of the button is the center, but there is trend towards moving it to a corner
-// where it gets out of the way of valuable content in the poster image.
-@big-play-align: left; // left, center, or right
-@big-play-vertical-align: top; // top, middle, or bottom
-// The button colors match the control colors by default but you can customize
-// them by replace the variables (@control-bg-color) with your own color values.
-@big-play-bg-color: @control-bg-color;
-@big-play-bg-alpha: @control-bg-alpha;
-// The font size is what makes the big play button, big. All width/height values
-// use ems, which are a multiple of the font size.
-// If the @base-font-size is 10px, then 3em equals 30px.
-@big-play-font-size: 3em;
-// Now that font size is set, the following em values will be a multiple of the
-// new font size. If @big-play-font-size is 3em (30px), then setting the any of
-// the following values to 2em would equal 60px. 2 * font-size
-@big-play-margin: 0.5em;
-@big-play-width: 4em;
-@big-play-height: 2.6em;
-@big-play-border-radius: 0.8em;
-@big-play-border-width: 0.1em;
-@big-play-border-color: #3b4249;
-
-/* SKIN
-================================================================================
-The main class name for all skin-specific styles. To make your own skin,
-replace all occurrences of 'vjs-default-skin' with a new name. Then add your new
-skin name to your video tag instead of the default skin.
-e.g.
-*/
-.vjs-default-skin {
- color: @main-font-color;
-}
-
-/* Custom Icon Font
---------------------------------------------------------------------------------
-The control icons are from a custom font. Each icon corresponds to a character
-(e.g. "\e001"). Font icons allow for easy scaling and coloring of icons.
-*/
-@vjs-font-path: 'font';
-@font-face{
- font-family: 'VideoJS';
- src: url('@{vjs-font-path}/vjs.eot');
- src: url('@{vjs-font-path}/vjs.eot?#iefix') format('embedded-opentype'),
- url('@{vjs-font-path}/vjs.woff') format('woff'),
- url('@{vjs-font-path}/vjs.ttf') format('truetype'),
- url('@{vjs-font-path}/vjs.svg#icomoon') format('svg');
-
- font-weight: normal;
- font-style: normal;
-}
-
-// Icon font character values
-@play-icon: "\e001";
-@pause-icon: "\e002";
-@volume-muted-icon: "\e003";
-@volume-low-icon: "\e004";
-@volume-mid-icon: "\e005";
-@volume-high-icon: "\e006";
-@fullscreen-enter-icon: "\e000";
-@fullscreen-exit-icon: "\e00b";
-@square-icon: "\e009";
-@spinner-icon: "\e00a";
-@spinner2-icon: "\e00d";
-@spinner3-icon: "\e01e";
-@spinner4-icon: "\e01f";
-@subtitles-icon: "\e00c";
-@captions-icon: "\e008";
-@chapters-icon: "\e00c";
-@share-icon: "\e00e";
-@cog-icon: "\e600";
-
-/* Base UI Component Classes
---------------------------------------------------------------------------------
-*/
-
-/* Slider - used for Volume bar and Seek bar */
-.vjs-default-skin .vjs-slider {
- /* Replace browser focus highlight with handle highlight *///
- outline: 0;
- position: relative;
- cursor: pointer;
- padding: 0;
-
- .background-color-with-alpha(@slider-background-color, @slider-background-alpha);
-}
-
-.vjs-default-skin .vjs-slider:focus {
- .box-shadow(0 0 2em #fff);
-}
-
-.vjs-default-skin .vjs-slider-handle {
- position: absolute;
- /* Needed for IE6 *///
- left: 0;
- top: 0;
-}
-
-.vjs-default-skin .vjs-slider-handle:before {
- content: @square-icon;
- font-family: VideoJS;
- font-size: 1em;
- line-height: 1;
- text-align: center;
- text-shadow: 0em 0em 1em #fff;
-
- position: absolute;
- top: 0;
- left: 0;
-
- /* Rotate the square icon to make a diamond *///
- .transform(rotate(-45deg));
-}
-
-/* Control Bar
---------------------------------------------------------------------------------
-The default control bar that is a container for most of the controls.
-*/
-.vjs-default-skin .vjs-control-bar {
- /* Start hidden *///
- display: none;
- position: absolute;
- /* Place control bar at the bottom of the player box/video.
- If you want more margin below the control bar, add more height. *///
- bottom: 0;
- /* Use left/right to stretch to 100% width of player div *///
- left: 0;
- right: 0;
- /* Height includes any margin you want above or below control items *///
- height: 3.0em;
-
- .background-color-with-alpha(@control-bg-color, @control-bg-alpha);
-}
-
-/* Show the control bar only once the video has started playing */
-.vjs-default-skin.vjs-has-started .vjs-control-bar {
- display: block;
- /* Visibility needed to make sure things hide in older browsers too. */
- visibility: visible;
- opacity: 1;
-
- @trans: visibility 0.1s, opacity 0.1s; // Var needed because of comma
- .transition(@trans);
-}
-
-/* Hide the control bar when the video is playing and the user is inactive */
-.vjs-default-skin.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar {
- display: block;
- visibility: hidden;
- opacity: 0;
-
- @trans: visibility 1.0s, opacity 1.0s;
- .transition(@trans);
-}
-
-.vjs-default-skin.vjs-controls-disabled .vjs-control-bar {
- display: none;
-}
-
-.vjs-default-skin.vjs-using-native-controls .vjs-control-bar {
- display: none;
-}
-
-/* The control bar shouldn't show after an error */
-.vjs-default-skin.vjs-error .vjs-control-bar {
- display: none;
-}
-
-/* Don't hide the control bar if it's audio */
-.vjs-audio.vjs-default-skin.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar {
- opacity: 1;
- visibility: visible;
-}
-
-/* IE8 is flakey with fonts, and you have to change the actual content to force
-fonts to show/hide properly.
- - "\9" IE8 hack didn't work for this
- - Found in XP IE8 from http://modern.ie. Does not show up in "IE8 mode" in IE9
-*/
-@ie8screen: ~"\0screen";
-.vjs-default-skin.vjs-user-inactive.vjs-playing .vjs-control-bar :before {
- @media @ie8screen { content: ""; }
-}
-
-/* General styles for individual controls. */
-.vjs-default-skin .vjs-control {
- outline: none;
- position: relative;
- float: left;
- text-align: center;
- margin: 0;
- padding: 0;
- height: 3.0em;
- width: 4em;
-}
-
-/* Font button icons */
-.vjs-default-skin .vjs-control:before {
- font-family: VideoJS;
- font-size: 1.5em;
- line-height: 2;
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- text-align: center;
- text-shadow: 1px 1px 1px rgba(0,0,0,0.5);
-}
-
-/* Replacement for focus outline */
-.vjs-default-skin .vjs-control:focus:before,
-.vjs-default-skin .vjs-control:hover:before {
- text-shadow: 0em 0em 1em rgba(255, 255, 255, 1);
-}
-
-.vjs-default-skin .vjs-control:focus {
- /* outline: 0; *///
- /* keyboard-only users cannot see the focus on several of the UI elements when
- this is set to 0 */
-}
-
-/* Hide control text visually, but have it available for screenreaders */
-.vjs-default-skin .vjs-control-text {
- .hide-visually;
-}
-
-/* Play/Pause
---------------------------------------------------------------------------------
-*/
-.vjs-default-skin .vjs-play-control {
- width: 5em;
- cursor: pointer;
-}
-.vjs-default-skin .vjs-play-control:before {
- content: @play-icon;
-}
-.vjs-default-skin.vjs-playing .vjs-play-control:before {
- content: @pause-icon;
-}
-
-/* Playback toggle
---------------------------------------------------------------------------------
-*/
-.vjs-default-skin .vjs-playback-rate .vjs-playback-rate-value {
- font-size: 1.5em;
- line-height: 2;
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- text-align: center;
- text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5);
-}
-
-.vjs-default-skin .vjs-playback-rate.vjs-menu-button .vjs-menu .vjs-menu-content {
- width: 4em;
- left: -2em;
- list-style: none;
-}
-
-/* Volume/Mute
--------------------------------------------------------------------------------- */
-.vjs-default-skin .vjs-mute-control,
-.vjs-default-skin .vjs-volume-menu-button {
- cursor: pointer;
- float: right;
-}
-.vjs-default-skin .vjs-mute-control:before,
-.vjs-default-skin .vjs-volume-menu-button:before {
- content: @volume-high-icon;
-}
-.vjs-default-skin .vjs-mute-control.vjs-vol-0:before,
-.vjs-default-skin .vjs-volume-menu-button.vjs-vol-0:before {
- content: @volume-muted-icon;
-}
-.vjs-default-skin .vjs-mute-control.vjs-vol-1:before,
-.vjs-default-skin .vjs-volume-menu-button.vjs-vol-1:before {
- content: @volume-low-icon;
-}
-.vjs-default-skin .vjs-mute-control.vjs-vol-2:before,
-.vjs-default-skin .vjs-volume-menu-button.vjs-vol-2:before {
- content: @volume-mid-icon;
-}
-
-.vjs-default-skin .vjs-volume-control {
- width: 5em;
- float: right;
-}
-.vjs-default-skin .vjs-volume-bar {
- width: 5em;
- height: 0.6em;
- margin: 1.1em auto 0;
-}
-
-.vjs-default-skin .vjs-volume-level {
- position: absolute;
- top: 0;
- left: 0;
- height: 0.5em;
- /* assuming volume starts at 1.0 */
- width: 100%;
-
- background: @slider-bar-color
- url(@slider-bar-pattern)
- -50% 0 repeat;
-}
-.vjs-default-skin .vjs-volume-bar .vjs-volume-handle {
- width: 0.5em;
- height: 0.5em;
- /* Assumes volume starts at 1.0. If you change the size of the
- handle relative to the volume bar, you'll need to update this value
- too. */
- left: 4.5em;
-}
-
-.vjs-default-skin .vjs-volume-handle:before {
- font-size: 0.9em;
- top: -0.2em;
- left: -0.2em;
-
- width: 1em;
- height: 1em;
-}
-
-/* The volume menu button is like menu buttons (captions/subtitles) but works
- a little differently. It needs to be possible to tab to the volume slider
- without hitting space bar on the menu button. To do this we're not using
- display:none to hide the slider menu by default, and instead setting the
- width and height to zero. */
-.vjs-default-skin .vjs-volume-menu-button .vjs-menu {
- display: block;
- width: 0;
- height: 0;
- border-top-color: transparent;
-}
-
-.vjs-default-skin .vjs-volume-menu-button .vjs-menu .vjs-menu-content {
- height: 0;
- width: 0;
-}
-
-.vjs-default-skin .vjs-volume-menu-button:hover .vjs-menu,
-.vjs-default-skin .vjs-volume-menu-button .vjs-menu.vjs-lock-showing {
- border-top-color: rgba(7, 40, 50, 0.5); /* Same as ul background */
-}
-
-.vjs-default-skin .vjs-volume-menu-button:hover .vjs-menu .vjs-menu-content,
-.vjs-default-skin .vjs-volume-menu-button .vjs-menu.vjs-lock-showing .vjs-menu-content {
- height: 2.9em;
- width: 10em;
-}
-
-/* Progress
---------------------------------------------------------------------------------
-*/
-.vjs-default-skin .vjs-progress-control {
- position: absolute;
- left: 0;
- right: 0;
- width: auto;
- font-size: 0.3em;
- height: 1em;
- /* Set above the rest of the controls. *///
- top: -1em;
-
- /* Shrink the bar slower than it grows. *///
- .transition(all 0.4s);
-}
-
-/* On hover, make the progress bar grow to something that's more clickable.
- This simply changes the overall font for the progress bar, and this
- updates both the em-based widths and heights, as wells as the icon font */
-.vjs-default-skin:hover .vjs-progress-control {
- font-size: .9em;
-
- /* Even though we're not changing the top/height, we need to include them in
- the transition so they're handled correctly. */
- .transition(all 0.2s);
-}
-
-/* Box containing play and load progresses. Also acts as seek scrubber. */
-.vjs-default-skin .vjs-progress-holder {
- height: 100%;
-}
-
-/* Progress Bars */
-.vjs-default-skin .vjs-progress-holder .vjs-play-progress,
-.vjs-default-skin .vjs-progress-holder .vjs-load-progress,
-.vjs-default-skin .vjs-progress-holder .vjs-load-progress div {
- position: absolute;
- display: block;
- height: 100%;
- margin: 0;
- padding: 0;
- /* updated by javascript during playback */
- width: 0;
- /* Needed for IE6 *///
- left: 0;
- top: 0;
-}
-
-.vjs-default-skin .vjs-play-progress {
- /*
- Using a data URI to create the white diagonal lines with a transparent
- background. Surprisingly works in IE8.
- Created using http://www.patternify.com
- Changing the first color value will change the bar color.
- Also using a paralax effect to make the lines move backwards.
- The -50% left position makes that happen.
- */
- background: @slider-bar-color
- url(@slider-bar-pattern)
- -50% 0 repeat;
-}
-.vjs-default-skin .vjs-load-progress {
- background: rgb(100, 100, 100) /* IE8- Fallback */;
- background: rgba(255, 255, 255, 0.2);
-}
-
-/* there are child elements of the load progress bar that represent the
- specific time ranges that have been buffered */
-.vjs-default-skin .vjs-load-progress div {
- background: rgb(120, 120, 120) /* IE8- Fallback */;
- background: rgba(255, 255, 255, 0.1);
-}
-
-.vjs-default-skin .vjs-seek-handle {
- width: 1.5em;
- height: 100%;
-}
-
-.vjs-default-skin .vjs-seek-handle:before {
- padding-top: 0.1em /* Minor adjustment */;
-}
-
-/* Live Mode
---------------------------------------------------------------------------------
-*/
-.vjs-default-skin.vjs-live .vjs-time-controls,
-.vjs-default-skin.vjs-live .vjs-time-divider,
-.vjs-default-skin.vjs-live .vjs-progress-control {
- display: none;
-}
-.vjs-default-skin.vjs-live .vjs-live-display {
- display: block;
-}
-
-/* Live Display
---------------------------------------------------------------------------------
-*/
-.vjs-default-skin .vjs-live-display {
- display: none;
- font-size: 1em;
- line-height: 3em;
-}
-
-/* Time Display
---------------------------------------------------------------------------------
-*/
-.vjs-default-skin .vjs-time-controls {
- font-size: 1em;
- /* Align vertically by making the line height the same as the control bar *///
- line-height: 3em;
-}
-.vjs-default-skin .vjs-current-time { float: left; }
-.vjs-default-skin .vjs-duration { float: left; }
-/* Remaining time is in the HTML, but not included in default design */
-.vjs-default-skin .vjs-remaining-time { display: none; float: left; }
-.vjs-time-divider { float: left; line-height: 3em; }
-
-/* Fullscreen
---------------------------------------------------------------------------------
-*/
-.vjs-default-skin .vjs-fullscreen-control {
- width: 3.8em;
- cursor: pointer;
- float: right;
-}
-.vjs-default-skin .vjs-fullscreen-control:before {
- content: @fullscreen-enter-icon;
-}
-/* Switch to the exit icon when the player is in fullscreen */
-.vjs-default-skin.vjs-fullscreen .vjs-fullscreen-control:before {
- content: @fullscreen-exit-icon;
-}
-
-/* Big Play Button (play button at start)
---------------------------------------------------------------------------------
-Positioning of the play button in the center or other corners can be done more
-easily in the skin designer. http://designer.videojs.com/
-*/
-.vjs-default-skin .vjs-big-play-button {
- // Calculate total width/height so we're able to center the button
- @total-width: (@big-play-width + (@big-play-border-width * 2));
- @total-height: (@big-play-height + (@big-play-border-width * 2));
- // Position the button using the absolute-align mixin (bottom of page)
- .absolute-align(@big-play-align, @big-play-margin, @total-width);
- .absolute-align(@big-play-vertical-align, @big-play-margin, @total-height);
-
- font-size: @big-play-font-size;
- display: block;
- z-index: 2;
- position: absolute;
- width: @big-play-width;
- height: @big-play-height;
- text-align: center;
- vertical-align: middle;
- cursor: pointer;
- opacity: 1;
-
- /* Need a slightly gray bg so it can be seen on black backgrounds *///
- .background-color-with-alpha(@big-play-bg-color, @big-play-bg-alpha);
-
- border: @big-play-border-width solid @big-play-border-color;
-
- .border-radius(@big-play-border-radius);
- .box-shadow(0px 0px 1em rgba(255, 255, 255, 0.25));
- .transition(all 0.4s);
-}
-
-/* Optionally center */
-.vjs-default-skin.vjs-big-play-centered .vjs-big-play-button {
- @total-width: (@big-play-width + (@big-play-border-width * 2));
- @total-height: (@big-play-height + (@big-play-border-width * 2));
-
- .absolute-align(center, @big-play-margin, @total-width);
- .absolute-align(middle, @big-play-margin, @total-height);
-}
-
-/* Hide if controls are disabled */
-.vjs-default-skin.vjs-controls-disabled .vjs-big-play-button {
- display: none;
-}
-/* Hide when video starts playing */
-.vjs-default-skin.vjs-has-started .vjs-big-play-button {
- display: none;
-}
-/* Hide on mobile devices. Remove when we stop using native controls
- by default on mobile */
-.vjs-default-skin.vjs-using-native-controls .vjs-big-play-button {
- display: none;
-}
-
-.vjs-default-skin:hover .vjs-big-play-button,
-.vjs-default-skin .vjs-big-play-button:focus {
- outline: 0;
- border-color: #fff;
- /* IE8 needs a non-glow hover state *///
- background-color: rgb(80, 80, 80);
- background-color: rgba(50, 50, 50, 0.75);
-
- .box-shadow(0 0 3em #fff);
- .transition(all 0s);
-}
-
-.vjs-default-skin .vjs-big-play-button:before {
- content: @play-icon;
- font-family: VideoJS;
- /* In order to center the play icon vertically we need to set the line height
- to the same as the button height */
- line-height: @big-play-height;
- text-shadow: 0.05em 0.05em 0.1em #000;
- text-align: center /* Needed for IE8 */;
-
- position: absolute;
- left: 0;
- width: 100%;
- height: 100%;
-}
-
-.vjs-error .vjs-big-play-button {
- display: none;
-}
-
-/* Error Display
---------------------------------------------------------------------------------
-*/
-
-.vjs-error-display {
- display: none;
-}
-
-.vjs-error .vjs-error-display {
- display: block;
- position: absolute;
- left: 0;
- top: 0;
- width: 100%;
- height: 100%;
-}
-
-.vjs-error .vjs-error-display:before {
- content: 'X';
- font-family: Arial;
- font-size: 4em;
- color: #666666;
- /* In order to center the play icon vertically we need to set the line height
- to the same as the button height */
- line-height: 1;
- text-shadow: 0.05em 0.05em 0.1em #000;
- text-align: center /* Needed for IE8 */;
- vertical-align: middle;
-
- position: absolute;
- left: 0;
- top: 50%;
- margin-top: -0.5em;
- width: 100%;
-}
-
-.vjs-error-display div {
- position: absolute;
- bottom: 1em;
- right: 0;
- left: 0;
-
- font-size: 1.4em;
- text-align: center;
- padding: 3px;
- background: rgb(0, 0, 0); // fallback to just black
- background: rgba(0,0,0,0.5); // Normally show black at 50% opacity
-}
-
-.vjs-error-display a, .vjs-error-display a:visited {
- color: #F4A460;
-}
-
-/* Loading Spinner
---------------------------------------------------------------------------------
-*/
-
-.vjs-loading-spinner {
- /* Should be hidden by default *///
- display: none;
-
- position: absolute;
- top: 50%;
- left: 50%;
-
- font-size: 4em;
- line-height: 1;
-
- width: 1em;
- height: 1em;
-
- margin-left: -0.5em;
- margin-top: -0.5em;
-
- opacity: 0.75;
-}
-
-/* Show the spinner when waiting for data and seeking to a new time */
-.vjs-waiting .vjs-loading-spinner,
-.vjs-seeking .vjs-loading-spinner {
- display: block;
-
- /* only animate when showing because it can be processor heavy *///
- .animation(spin 1.5s infinite linear);
-}
-
-/* Errors are unrecoverable without user interaction so hide the spinner */
-.vjs-error .vjs-loading-spinner {
- display: none;
-
- /* ensure animation doesn't continue while hidden *///
- .animation(none);
-}
-
-.vjs-default-skin .vjs-loading-spinner:before {
- content: @spinner3-icon;
- font-family: VideoJS;
-
- position: absolute;
- top: 0;
- left: 0;
- width: 1em;
- height: 1em;
- text-align: center;
- text-shadow: 0em 0em 0.1em #000;
-}
-
-@-moz-keyframes spin {
- 0% { -moz-transform: rotate(0deg); }
- 100% { -moz-transform: rotate(359deg); }
-}
-@-webkit-keyframes spin {
- 0% { -webkit-transform: rotate(0deg); }
- 100% { -webkit-transform: rotate(359deg); }
-}
-@-o-keyframes spin {
- 0% { -o-transform: rotate(0deg); }
- 100% { -o-transform: rotate(359deg); }
-}
-@keyframes spin {
- 0% { transform: rotate(0deg); }
- 100% { transform: rotate(359deg); }
-}
-
-/* Menu Buttons (Captions/Subtitles/etc.)
---------------------------------------------------------------------------------
-*/
-.vjs-default-skin .vjs-menu-button {
- float: right;
- cursor: pointer;
-}
-
-.vjs-default-skin .vjs-menu {
- display: none;
- position: absolute;
- bottom: 0;
- left: 0em; /* (Width of vjs-menu - width of button) / 2 */
- width: 0em;
- height: 0em;
- margin-bottom: 3em;
-
- border-left: 2em solid transparent;
- border-right: 2em solid transparent;
-
- border-top: 1.55em solid rgb(0, 0, 0); /* Same width top as ul bottom */
- border-top-color: rgba(7, 40, 50, 0.5); /* Same as ul background */
-}
-
-/* Button Pop-up Menu */
-.vjs-default-skin .vjs-menu-button .vjs-menu .vjs-menu-content {
- display: block;
- padding: 0; margin: 0;
- position: absolute;
- width: 10em;
- bottom: 1.5em; /* Same bottom as vjs-menu border-top */
- max-height: 15em;
- overflow: auto;
-
- left: -5em; /* Width of menu - width of button / 2 */
-
- .background-color-with-alpha(@control-bg-color, @control-bg-alpha);
- .box-shadow(-0.2em -0.2em 0.3em rgba(255, 255, 255, 0.2));
-}
-
-.vjs-default-skin .vjs-menu-button:hover .vjs-control-content .vjs-menu,
-.vjs-default-skin .vjs-control-content .vjs-menu.vjs-lock-showing {
- display: block;
-}
-/* prevent menus from opening while scrubbing (FF, IE) */
-.vjs-default-skin.vjs-scrubbing .vjs-menu-button:hover .vjs-control-content .vjs-menu {
- display: none;
-}
-.vjs-default-skin .vjs-menu-button ul li {
- list-style: none;
- margin: 0;
- padding: 0.3em 0 0.3em 0;
- line-height: 1.4em;
- font-size: 1.2em;
- text-align: center;
- text-transform: lowercase;
-}
-.vjs-default-skin .vjs-menu-button ul li.vjs-selected {
- background-color: #000;
-}
-.vjs-default-skin .vjs-menu-button ul li:focus,
-.vjs-default-skin .vjs-menu-button ul li:hover,
-.vjs-default-skin .vjs-menu-button ul li.vjs-selected:focus,
-.vjs-default-skin .vjs-menu-button ul li.vjs-selected:hover {
- outline: 0;
- color: #111;
-
- .background-color-with-alpha(rgb(255, 255, 255), 0.75);
- .box-shadow(0 0 1em rgba(255, 255, 255, 1));
-}
-.vjs-default-skin .vjs-menu-button ul li.vjs-menu-title {
- text-align: center;
- text-transform: uppercase;
- font-size: 1em;
- line-height: 2em;
- padding: 0;
- margin: 0 0 0.3em 0;
- font-weight: bold;
- cursor: default;
-}
-
-/* Subtitles Button */
-.vjs-default-skin .vjs-subtitles-button:before {
- content: @subtitles-icon;
-}
-
-/* Captions Button */
-.vjs-default-skin .vjs-captions-button:before {
- content: @captions-icon;
-}
-
-/* Chapters Button */
-.vjs-default-skin .vjs-chapters-button:before {
- content: @chapters-icon;
-}
-
-.vjs-default-skin .vjs-chapters-button.vjs-menu-button .vjs-menu .vjs-menu-content {
- width: 24em;
- left: -12em;
-}
-
-/* Replacement for focus outline */
-.vjs-default-skin .vjs-captions-button:focus .vjs-control-content:before,
-.vjs-default-skin .vjs-captions-button:hover .vjs-control-content:before {
- .box-shadow(0 0 1em rgba(255, 255, 255, 1));
-}
-
-/*
-REQUIRED STYLES (be careful overriding)
-================================================================================
-When loading the player, the video tag is replaced with a DIV,
-that will hold the video tag or object tag for other playback methods.
-The div contains the video playback element (Flash or HTML5) and controls,
-and sets the width and height of the video.
-
-** If you want to add some kind of border/padding (e.g. a frame), or special
-positioning, use another containing element. Otherwise you risk messing up
-control positioning and full window mode. **
-*/
-.video-js {
- background-color: #000;
- position: relative;
- padding: 0;
- /* Start with 10px for base font size so other dimensions can be em based and
- easily calculable. */
- font-size: @base-font-size;
- /* Allow poster to be vertically aligned. */
- vertical-align: middle;
- /* display: table-cell; */ /*This works in Safari but not Firefox.*/
-
- /* Provide some basic defaults for fonts */
- font-weight: normal;
- font-style: normal;
- /* Avoiding helvetica: issue #376 */
- font-family: Arial, sans-serif;
-
- /* Turn off user selection (text highlighting) by default.
- The majority of player components will not be text blocks.
- Text areas will need to turn user selection back on. */
- .user-select(none);
-}
-
-/* Playback technology elements expand to the width/height of the containing div
- or */
-.video-js .vjs-tech {
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
-}
-
-/* Fix for Firefox 9 fullscreen (only if it is enabled). Not needed when
- checking fullScreenEnabled. */
-.video-js:-moz-full-screen { position: absolute; }
-
-/* Fullscreen Styles */
-body.vjs-full-window {
- padding: 0;
- margin: 0;
- height: 100%;
- /* Fix for IE6 full-window. http://www.cssplay.co.uk/layouts/fixed.html *///
- overflow-y: auto;
-}
-.video-js.vjs-fullscreen {
- position: fixed;
- overflow: hidden;
- z-index: 1000;
- left: 0;
- top: 0;
- bottom: 0;
- right: 0;
- width: 100% !important;
- height: 100% !important;
- /* IE6 full-window (underscore hack) *///
- _position: absolute;
-}
-.video-js:-webkit-full-screen {
- width: 100% !important;
- height: 100% !important;
-}
-.video-js.vjs-fullscreen.vjs-user-inactive {
- cursor: none;
-}
-
-/* Poster Styles */
-.vjs-poster {
- background-repeat: no-repeat;
- background-position: 50% 50%;
- background-size: contain;
- cursor: pointer;
- margin: 0;
- padding: 0;
- position: absolute;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
-}
-.vjs-poster img {
- display: block;
- margin: 0 auto;
- max-height: 100%;
- padding: 0;
- width: 100%;
-}
-
-/* Hide the poster after the video has started playing */
-.video-js.vjs-has-started .vjs-poster {
- display: none;
-}
-
-/* Don't hide the poster if we're playing audio */
-.video-js.vjs-audio.vjs-has-started .vjs-poster {
- display: block;
-}
-
-/* Hide the poster when controls are disabled because it's clickable
- and the native poster can take over */
-.video-js.vjs-controls-disabled .vjs-poster {
- display: none;
-}
-
-/* Hide the poster when native controls are used otherwise it covers them */
-.video-js.vjs-using-native-controls .vjs-poster {
- display: none;
-}
-
-/* Text Track Styles */
-/* Overall track holder for both captions and subtitles */
-.video-js .vjs-text-track-display {
- position: absolute;
- top: 0;
- left: 0;
- bottom: 3em;
- right: 0;
- pointer-events: none;
-}
-
-/* Captions Settings Dialog */
-.vjs-caption-settings {
- position: relative;
- top: 1em;
- background-color: #000;
- opacity: 0.75;
- color: #FFF;
- margin: 0 auto;
- padding: 0.5em;
- height: 15em;
- font-family: Arial, Helvetica, sans-serif;
- font-size: 12px;
- width: 40em;
-}
-
-.vjs-caption-settings .vjs-tracksettings {
- top: 0;
- bottom: 2em;
- left: 0;
- right: 0;
- position: absolute;
- overflow: auto;
-}
-
-.vjs-caption-settings .vjs-tracksettings-colors,
-.vjs-caption-settings .vjs-tracksettings-font {
- float: left;
-}
-.vjs-caption-settings .vjs-tracksettings-colors:after,
-.vjs-caption-settings .vjs-tracksettings-font:after,
-.vjs-caption-settings .vjs-tracksettings-controls:after {
- clear: both;
-}
-
-.vjs-caption-settings .vjs-tracksettings-controls {
- position: absolute;
- bottom: 1em;
- right: 1em;
-}
-
-.vjs-caption-settings .vjs-tracksetting {
- margin: 5px;
- padding: 3px;
- min-height: 40px;
-}
-.vjs-caption-settings .vjs-tracksetting label {
- display: block;
- width: 100px;
- margin-bottom: 5px;
-}
-
-.vjs-caption-settings .vjs-tracksetting span {
- display: inline;
- margin-left: 5px;
-}
-
-.vjs-caption-settings .vjs-tracksetting > div {
- margin-bottom: 5px;
- min-height: 20px;
-}
-
-.vjs-caption-settings .vjs-tracksetting > div:last-child {
- margin-bottom: 0;
- padding-bottom: 0;
- min-height: 0;
-}
-
-.vjs-caption-settings label > input {
- margin-right: 10px;
-}
-
-.vjs-caption-settings input[type="button"] {
- width: 40px;
- height: 40px;
-}
-
-/* Hide disabled or unsupported controls */
-.vjs-hidden { display: none !important; }
-
-.vjs-lock-showing {
- display: block !important;
- opacity: 1;
- visibility: visible;
-}
-
-/* In IE8 w/ no JavaScript (no HTML5 shim), the video tag doesn't register.
- The .video-js classname on the video tag also isn't considered.
- This optional paragraph inside the video tag can provide a message to users
- about what's required to play video. */
-.vjs-no-js {
- padding: 2em;
- color: #ccc;
- background-color: #333;
- font-size: 1.8em;
- font-family: Arial, sans-serif;
- text-align: center;
- width: 30em;
- height: 15em;
- margin: 0 auto;
-}
-
-.vjs-no-js a, .vjs-no-js a:visited {
- color: #F4A460;
-}
-
-// MIXINS
-// =============================================================================
-// Mixins are a LESS feature and are used to add vendor prefixes to CSS rules
-// when needed.
-
-// https://developer.mozilla.org/en-US/docs/Web/CSS/box-shadow
-.box-shadow (@string: 0 0 1em rgba(0, 0, 0, 0.25)) {
- /* box-shadow *///
- -webkit-box-shadow: @string;
- -moz-box-shadow: @string;
- box-shadow: @string;
-}
-
-// https://developer.mozilla.org/en-US/docs/Web/CSS/border-radius
-.border-radius (@string: 5px) {
- /* border-radius *///
- -webkit-border-radius: @string;
- -moz-border-radius: @string;
- border-radius: @string;
-}
-
-// https://developer.mozilla.org/en-US/docs/Web/CSS/transition
-.transition (@string: all 1s linear) {
- /* transition *///
- -webkit-transition: @string;
- -moz-transition: @string;
- -o-transition: @string;
- transition: @string;
-}
-
-// https://developer.mozilla.org/en-US/docs/Web/CSS/transition
-.transition-delay (@string: 1s) {
- /* transition-delay *///
- -webkit-transition-delay: @string;
- -moz-transition-delay: @string;
- -o-transition-delay: @string;
- transition-delay: @string;
-}
-
-// https://developer.mozilla.org/en-US/docs/Web/CSS/animation
-.animation (@string: spin 1s infinite linear) {
- /* animation *///
- -webkit-animation: @string;
- -moz-animation: @string;
- -o-animation: @string;
- animation: @string;
-}
-
-// https://developer.mozilla.org/en-US/docs/Web/CSS/transform
-.transform (@string: rotate(-45deg)) {
- /* transform *///
- -webkit-transform: @string;
- -moz-transform: @string;
- -ms-transform: @string;
- -o-transform: @string;
- transform: @string;
-}
-
-// https://developer.mozilla.org/en-US/docs/Web/CSS/user-select
-.user-select (@string: none) {
- /* user-select *///
- -webkit-user-select: @string;
- -moz-user-select: @string;
- -ms-user-select: @string;
- user-select: @string;
-}
-
-// Hide something visually but keep available for screen readers.
-// http://h5bp.com/v
-.hide-visually () {
- /* hide-visually *///
- border: 0;
- clip: rect(0 0 0 0);
- height: 1px;
- margin: -1px;
- overflow: hidden;
- padding: 0;
- position:
- absolute;
- width: 1px;
-}
-
-// Align an object with absolute positioning
-// Used to align the Big Play Button in the corners or center
-.absolute-align (@align, @margin, @length) when (@align = top) {
- top: @margin;
-}
-.absolute-align (@align, @margin, @length) when (@align = bottom) {
- bottom: @margin;
-}
-.absolute-align (@align, @margin, @length) when (@align = left) {
- left: @margin;
-}
-.absolute-align (@align, @margin, @length) when (@align = right) {
- right: @margin;
-}
-.absolute-align (@align, @margin, @length) when (@align = center) {
- /* Center it horizontally *///
- left: 50%;
- margin-left: (-(@length/2));
- // margin-left: ((@length*-1)/2);
-}
-.absolute-align (@align, @margin, @length) when (@align = middle) {
- /* Center it vertically *///
- top: 50%;
- margin-top: (-(@length/2));
- // margin-top: ((@length*-1)/2);
-}
-
-// http://stackoverflow.com/questions/637921/opacity-of-background-but-not-the-text
-.background-color-with-alpha (@color, @alpha) {
- @rgba: rgba(red(@color), green(@color), blue(@color), @alpha);
- /* background-color-with-alpha *///
- background-color: @color;
- background-color: @rgba;
- // No longer using MS filters because they break border radius in IE9
- // @argb: argb(@rgba);
- // filter: ~"progid:DXImageTransform.Microsoft.gradient(startColorstr=@{argb}, endColorstr=@{argb})";
- // -ms-filter: ~"progid:DXImageTransform.Microsoft.gradient(startColorstr=@{argb}, endColorstr=@{argb})";
-}
-
-.border-color-with-alpha (@color, @alpha) {
- @rgba: rgba(red(@color), green(@color), blue(@color), @alpha);
- /* border-color-with-alpha *///
- border-color: @color;
- border-color: @rgba;
-}
-
-// NOTES ON LESS (tracking learnings so we don't forget)
-// =============================================================================
-// * We want this file to continue to be accessible by people who don't know
-// LESS but know CSS. This means finding the balance between using the most
-// valuable LESS features (e.g. variables) and keeping it looking like CSS.
-// So it's best to avoid advanced LESS features like conditional statements.
-// (we're using one for the big play button position because that's a hot
-// topic)
-//
-// * We care about the readability of the CSS output of LESS, which means we
-// have to be careful about what features of LESS we use. (if you're building
-// your own skin this may not apply)
-// 1. Comments inside of rules (strangely) have an extra line added after
-// them in the CSS output. To avoid this we can add a LESS comment after
-// the CSS comment.
-// /* comment *///
-//
-// 2. In a rule with nested rules, any comments outside of a rule are moved
-// to the top of the parent rule. i.e. it might look like:
-// /* title of rule 1 */
-// /* title of rule 2 */
-// .rule1 {}
-// .rule2 {}
-// This is why we aren't using nested rules inside of the
-// vjs-default-skin class.
-
-/* -----------------------------------------------------------------------------
-The original source of this file lives at
-https://github.com/videojs/video.js/blob/master/src/css/video-js.less */
diff --git a/src/css/video-js.scss b/src/css/video-js.scss
new file mode 100644
index 000000000..8cff891c7
--- /dev/null
+++ b/src/css/video-js.scss
@@ -0,0 +1,25 @@
+@import "variables";
+@import "utilities";
+
+@import "components/icons";
+@import "components/layout";
+@import "components/big-play";
+@import "components/control-bar";
+@import "components/control";
+@import "components/progress";
+@import "components/slider";
+@import "components/volume";
+@import "components/menu";
+@import "components/poster";
+@import "components/live";
+@import "components/time";
+@import "components/play-pause";
+@import "components/text-track";
+@import "components/fullscreen";
+@import "components/playback-rate";
+@import "components/error";
+@import "components/loading";
+@import "components/captions";
+@import "components/chapters";
+@import "components/subtitles";
+@import "components/adaptive";
diff --git a/src/js/base-styles.js b/src/js/base-styles.js
new file mode 100644
index 000000000..d117d3780
--- /dev/null
+++ b/src/js/base-styles.js
@@ -0,0 +1,16 @@
+/**
+* This code injects the required base styles in the head of the document.
+*/
+import window from 'global/window';
+import document from 'global/document';
+
+if (window.VIDEOJS_NO_BASE_THEME) return;
+
+const styles = '{{GENERATED_STYLES}}';
+
+if (styles === '{{GENERATED'+'_STYLES}}');
+
+const styleNode = document.createElement('style');
+styleNode.innerHTML = styles;
+
+document.head.insertBefore(styleNode, document.head.firstChild);
diff --git a/src/js/big-play-button.js b/src/js/big-play-button.js
index 982c82751..361be7a98 100644
--- a/src/js/big-play-button.js
+++ b/src/js/big-play-button.js
@@ -5,7 +5,7 @@ import Button from './button';
/**
* Initial play button. Shows before the video has played. The hiding of the
* big play button is done via CSS and player states.
- * @param {vjs.Player|Object} player
+ * @param {Player|Object} player
* @param {Object=} options
* @class
* @constructor
@@ -20,7 +20,7 @@ class BigPlayButton extends Button {
});
}
- onClick() {
+ handleClick() {
this.player_.play();
}
diff --git a/src/js/button.js b/src/js/button.js
index dda2f7fd9..1c370c789 100644
--- a/src/js/button.js
+++ b/src/js/button.js
@@ -7,7 +7,7 @@ import document from 'global/document';
================================================================================ */
/**
* Base class for all buttons
- * @param {vjs.Player|Object} player
+ * @param {Player|Object} player
* @param {Object=} options
* @class
* @constructor
@@ -19,10 +19,10 @@ class Button extends Component {
this.emitTapEvents();
- this.on('tap', this.onClick);
- this.on('click', this.onClick);
- this.on('focus', this.onFocus);
- this.on('blur', this.onBlur);
+ this.on('tap', this.handleClick);
+ this.on('click', this.handleClick);
+ this.on('focus', this.handleFocus);
+ this.on('blur', this.handleBlur);
}
createEl(type, props) {
@@ -55,30 +55,29 @@ class Button extends Component {
}
buildCSSClass() {
- // TODO: Change vjs-control to vjs-button?
- return 'vjs-control ' + super.buildCSSClass();
+ return `vjs-control vjs-button ${super.buildCSSClass()}`;
}
// Click - Override with specific functionality for button
- onClick() {}
+ handleClick() {}
// Focus - Add keyboard functionality to element
- onFocus() {
- Events.on(document, 'keydown', Lib.bind(this, this.onKeyPress));
+ handleFocus() {
+ Events.on(document, 'keydown', Lib.bind(this, this.handleKeyPress));
}
// KeyPress (document level) - Trigger click when keys are pressed
- onKeyPress(event) {
+ handleKeyPress(event) {
// Check for space bar (32) or enter (13) keys
if (event.which == 32 || event.which == 13) {
event.preventDefault();
- this.onClick();
+ this.handleClick();
}
}
// Blur - Remove keyboard triggers
- onBlur() {
- Events.off(document, 'keydown', Lib.bind(this, this.onKeyPress));
+ handleBlur() {
+ Events.off(document, 'keydown', Lib.bind(this, this.handleKeyPress));
}
}
diff --git a/src/js/component.js b/src/js/component.js
index 2694a2fc6..edaee5b14 100644
--- a/src/js/component.js
+++ b/src/js/component.js
@@ -35,7 +35,6 @@ import window from 'global/window';
* @param {Object=} options
* @class
* @constructor
- * @extends vjs.CoreObject
*/
class Component {
@@ -60,7 +59,8 @@ class Component {
// If there was no ID from the options, generate one
if (!this.id_) {
// Don't require the player ID function in the case of mock players
- this.id_ = ((player.id && player.id()) || 'no_player') + '_component_' + Lib.guid++;
+ let id = player.id && player.id() || 'no_player';
+ this.id_ = `${id}_component_${Lib.guid++}`;
}
this.name_ = options['name'] || null;
@@ -131,7 +131,7 @@ class Component {
/**
* Return the component's player
*
- * @return {vjs.Player}
+ * @return {Player}
*/
player() {
return this.player_;
@@ -141,7 +141,7 @@ class Component {
* Deep merge of options objects
*
* Whenever a property is an object on both options objects
- * the two properties will be merged using vjs.obj.deepMerge.
+ * the two properties will be merged using Lib.obj.deepMerge.
*
* This is used for merging options for child components. We
* want it to be easy to override individual options on a child
@@ -207,11 +207,13 @@ class Component {
}
localize(string){
- var lang = this.player_.language(),
- languages = this.player_.languages();
+ let lang = this.player_.language();
+ let languages = this.player_.languages();
+
if (languages && languages[lang] && languages[lang][string]) {
return languages[lang][string];
}
+
return string;
}
@@ -261,7 +263,7 @@ class Component {
/**
* Returns a child component with the provided ID
*
- * @return {vjs.Component}
+ * @return {Component}
*/
getChildById(id){
return this.childIndex_[id];
@@ -270,7 +272,7 @@ class Component {
/**
* Returns a child component with the provided name
*
- * @return {vjs.Component}
+ * @return {Component}
*/
getChild(name){
return this.childNameIndex_[name];
@@ -299,21 +301,27 @@ class Component {
* }
* });
*
- * @param {String|vjs.Component} child The class name or instance of a child to add
+ * @param {String|Component} child The class name or instance of a child to add
* @param {Object=} options Options, including options to be passed to children of the child.
- * @return {vjs.Component} The child component (created by this process if a string was used)
+ * @return {Component} The child component (created by this process if a string was used)
* @suppress {accessControls|checkRegExp|checkTypes|checkVars|const|constantProperty|deprecated|duplicate|es5Strict|fileoverviewTags|globalThis|invalidCasts|missingProperties|nonStandardJsDocs|strictModuleDepCheck|undefinedNames|undefinedVars|unknownDefines|uselessCode|visibility}
*/
- addChild(child, options){
+ addChild(child, options={}){
let component;
let componentName;
// If child is a string, create nt with options
if (typeof child === 'string') {
- let componentName = child;
+ componentName = child;
- // Make sure options is at least an empty object to protect against errors
- if (!options || options === true) {
+ // Options can also be specified as a boolean, so convert to an empty object if false.
+ if (!options) {
+ options = {};
+ }
+
+ // Same as above, but true is deprecated so show a warning.
+ if (options === true) {
+ Lib.log.warn('Initializing a child component with `true` is deprecated. Children should be defined in an array when possible, but if necessary use an object instead of `true`.');
options = {};
}
@@ -326,8 +334,6 @@ class Component {
// Create a new object & element for this controls set
// If there's no .player_, this is a player
- // Closure Compiler throws an 'incomplete alias' warning if we use the vjs variable directly.
- // Every class should be exported, so this should never be a problem here.
let componentClass = Component.getComponent(componentClassName);
component = new componentClass(this.player_ || this, options);
@@ -365,7 +371,7 @@ class Component {
* Remove a child component from this component's list of children, and the
* child component's element from this component's element
*
- * @param {vjs.Component} component Component to remove
+ * @param {Component} component Component to remove
*/
removeChild(component){
if (typeof component === 'string') {
@@ -443,7 +449,7 @@ class Component {
}
// Allow for disabling default components
- // e.g. vjs.options['children']['posterImage'] = false
+ // e.g. options['children']['posterImage'] = false
if (opts === false) return;
// Create and add the child component.
@@ -505,36 +511,34 @@ class Component {
* myComponent.on(otherElement, 'eventName', myFunc);
* myComponent.on(otherComponent, 'eventName', myFunc);
*
- * The benefit of using this over `vjs.on(otherElement, 'eventName', myFunc)`
+ * The benefit of using this over `VjsEvents.on(otherElement, 'eventName', myFunc)`
* and `otherComponent.on('eventName', myFunc)` is that this way the listeners
* will be automatically cleaned up when either component is disposed.
* It will also bind myComponent as the context of myFunc.
*
* **NOTE**: When using this on elements in the page other than window
* and document (both permanent), if you remove the element from the DOM
- * you need to call `vjs.trigger(el, 'dispose')` on it to clean up
+ * you need to call `myComponent.trigger(el, 'dispose')` on it to clean up
* references to it and allow the browser to garbage collect it.
*
- * @param {String|vjs.Component} first The event type or other component
+ * @param {String|Component} first The event type or other component
* @param {Function|String} second The event handler or event type
* @param {Function} third The event handler
- * @return {vjs.Component} self
+ * @return {Component} self
*/
on(first, second, third){
- var target, type, fn, removeOnDispose, cleanRemover, thisComponent;
-
if (typeof first === 'string' || Lib.obj.isArray(first)) {
Events.on(this.el_, first, Lib.bind(this, second));
// Targeting another component or element
} else {
- target = first;
- type = second;
- fn = Lib.bind(this, third);
- thisComponent = this;
+ const target = first;
+ const type = second;
+ const fn = Lib.bind(this, third);
+ const thisComponent = this;
// When this component is disposed, remove the listener from the other component
- removeOnDispose = function(){
+ const removeOnDispose = function(){
thisComponent.off(target, type, fn);
};
// Use the same function ID so we can remove it later it using the ID
@@ -545,7 +549,7 @@ class Component {
// If the other component is disposed first we need to clean the reference
// to the other component in this component's removeOnDispose listener
// Otherwise we create a memory leak.
- cleanRemover = function(){
+ const cleanRemover = function(){
thisComponent.off('dispose', removeOnDispose);
};
// Add the same function ID so we can easily remove it later
@@ -558,7 +562,7 @@ class Component {
Events.on(target, 'dispose', cleanRemover);
// Should be a component
- // Not using `instanceof vjs.Component` because it makes mock players difficult
+ // Not using `instanceof Component` because it makes mock players difficult
} else if (typeof first.on === 'function') {
// Add the listener to the other component
target.on(type, fn);
@@ -584,21 +588,19 @@ class Component {
* myComponent.off(otherElement, 'eventType', myFunc);
* myComponent.off(otherComponent, 'eventType', myFunc);
*
- * @param {String=|vjs.Component} first The event type or other component
+ * @param {String=|Component} first The event type or other component
* @param {Function=|String} second The listener function or event type
* @param {Function=} third The listener for other component
- * @return {vjs.Component}
+ * @return {Component}
*/
off(first, second, third){
- var target, otherComponent, type, fn, otherEl;
-
if (!first || typeof first === 'string' || Lib.obj.isArray(first)) {
Events.off(this.el_, first, second);
} else {
- target = first;
- type = second;
+ const target = first;
+ const type = second;
// Ensure there's at least a guid, even if the function hasn't been used
- fn = Lib.bind(this, third);
+ const fn = Lib.bind(this, third);
// Remove the dispose listener on this component,
// which was given the same guid as the event listener
@@ -629,23 +631,21 @@ class Component {
* myComponent.one(otherElement, 'eventName', myFunc);
* myComponent.one(otherComponent, 'eventName', myFunc);
*
- * @param {String|vjs.Component} first The event type or other component
+ * @param {String|Component} first The event type or other component
* @param {Function|String} second The listener function or event type
* @param {Function=} third The listener function for other component
- * @return {vjs.Component}
+ * @return {Component}
*/
one(first, second, third) {
- var target, type, fn, thisComponent, newFunc;
-
if (typeof first === 'string' || Lib.obj.isArray(first)) {
Events.one(this.el_, first, Lib.bind(this, second));
} else {
- target = first;
- type = second;
- fn = Lib.bind(this, third);
- thisComponent = this;
+ const target = first;
+ const type = second;
+ const fn = Lib.bind(this, third);
+ const thisComponent = this;
- newFunc = function(){
+ const newFunc = function(){
thisComponent.off(target, type, newFunc);
fn.apply(this, arguments);
};
@@ -665,7 +665,7 @@ class Component {
* myComponent.trigger({'type':'eventName'});
*
* @param {Event|Object|String} event A string (the type) or an event object with a type attribute
- * @return {vjs.Component} self
+ * @return {Component} self
*/
trigger(event){
Events.trigger(this.el_, event);
@@ -679,7 +679,7 @@ class Component {
* it will trigger the function immediately.
*
* @param {Function} fn Ready listener
- * @return {vjs.Component}
+ * @return {Component}
*/
ready(fn){
if (fn) {
@@ -696,7 +696,7 @@ class Component {
/**
* Trigger the ready listeners
*
- * @return {vjs.Component}
+ * @return {Component}
*/
triggerReady(){
this.isReady_ = true;
@@ -721,7 +721,7 @@ class Component {
* Check if a component's element has a CSS class name
*
* @param {String} classToCheck Classname to check
- * @return {vjs.Component}
+ * @return {Component}
*/
hasClass(classToCheck){
return Lib.hasClass(this.el_, classToCheck);
@@ -731,7 +731,7 @@ class Component {
* Add a CSS class name to the component's element
*
* @param {String} classToAdd Classname to add
- * @return {vjs.Component}
+ * @return {Component}
*/
addClass(classToAdd){
Lib.addClass(this.el_, classToAdd);
@@ -742,7 +742,7 @@ class Component {
* Remove a CSS class name from the component's element
*
* @param {String} classToRemove Classname to remove
- * @return {vjs.Component}
+ * @return {Component}
*/
removeClass(classToRemove){
Lib.removeClass(this.el_, classToRemove);
@@ -752,7 +752,7 @@ class Component {
/**
* Show the component element if hidden
*
- * @return {vjs.Component}
+ * @return {Component}
*/
show(){
this.removeClass('vjs-hidden');
@@ -762,7 +762,7 @@ class Component {
/**
* Hide the component element if currently showing
*
- * @return {vjs.Component}
+ * @return {Component}
*/
hide(){
this.addClass('vjs-hidden');
@@ -773,7 +773,7 @@ class Component {
* Lock an item in its visible state
* To be used with fadeIn/fadeOut.
*
- * @return {vjs.Component}
+ * @return {Component}
* @private
*/
lockShowing(){
@@ -785,7 +785,7 @@ class Component {
* Unlock an item to be hidden
* To be used with fadeIn/fadeOut.
*
- * @return {vjs.Component}
+ * @return {Component}
* @private
*/
unlockShowing(){
@@ -803,7 +803,7 @@ class Component {
*
* @param {Number|String=} num Optional width number
* @param {Boolean} skipListeners Skip the 'resize' event trigger
- * @return {vjs.Component} This component, when setting the width
+ * @return {Component} This component, when setting the width
* @return {Number|String} The width, when getting
*/
width(num, skipListeners){
@@ -820,7 +820,7 @@ class Component {
*
* @param {Number|String=} num New component height
* @param {Boolean=} skipListeners Skip the resize event trigger
- * @return {vjs.Component} This component, when setting the height
+ * @return {Component} This component, when setting the height
* @return {Number|String} The height, when getting
*/
height(num, skipListeners){
@@ -832,7 +832,7 @@ class Component {
*
* @param {Number|String} width
* @param {Number|String} height
- * @return {vjs.Component} The component
+ * @return {Component} The component
*/
dimensions(width, height){
// Skip resize listeners on width for optimization
@@ -853,7 +853,7 @@ class Component {
* @param {String} widthOrHeight 'width' or 'height'
* @param {Number|String=} num New dimension
* @param {Boolean=} skipListeners Skip resize event trigger
- * @return {vjs.Component} The component if a dimension was set
+ * @return {Component} The component if a dimension was set
* @return {Number|String} The dimension if nothing was set
* @private
*/
@@ -902,7 +902,7 @@ class Component {
// Only difference is if the element is hidden it will return
// the percent value (e.g. '100%'')
// instead of zero like offsetWidth returns.
- // var val = vjs.getComputedStyleValue(this.el_, widthOrHeight);
+ // var val = Lib.getComputedStyleValue(this.el_, widthOrHeight);
// var pxIndex = val.indexOf('px');
// if (pxIndex !== -1) {
@@ -924,20 +924,18 @@ class Component {
* @private
*/
emitTapEvents(){
- var touchStart, firstTouch, touchTime, couldBeTap, noTap,
- xdiff, ydiff, touchDistance, tapMovementThreshold, touchTimeThreshold;
-
// Track the start time so we can determine how long the touch lasted
- touchStart = 0;
- firstTouch = null;
+ let touchStart = 0;
+ let firstTouch = null;
// Maximum movement allowed during a touch event to still be considered a tap
// Other popular libs use anywhere from 2 (hammer.js) to 15, so 10 seems like a nice, round number.
- tapMovementThreshold = 10;
+ const tapMovementThreshold = 10;
// The maximum length a touch can be while still being considered a tap
- touchTimeThreshold = 200;
+ const touchTimeThreshold = 200;
+ let couldBeTap;
this.on('touchstart', function(event) {
// If more than one finger, don't consider treating this as a click
if (event.touches.length === 1) {
@@ -956,16 +954,16 @@ class Component {
} else if (firstTouch) {
// Some devices will throw touchmoves for all but the slightest of taps.
// So, if we moved only a small distance, this could still be a tap
- xdiff = event.touches[0].pageX - firstTouch.pageX;
- ydiff = event.touches[0].pageY - firstTouch.pageY;
- touchDistance = Math.sqrt(xdiff * xdiff + ydiff * ydiff);
+ const xdiff = event.touches[0].pageX - firstTouch.pageX;
+ const ydiff = event.touches[0].pageY - firstTouch.pageY;
+ const touchDistance = Math.sqrt(xdiff * xdiff + ydiff * ydiff);
if (touchDistance > tapMovementThreshold) {
couldBeTap = false;
}
}
});
- noTap = function(){
+ const noTap = function(){
couldBeTap = false;
};
// TODO: Listen to the original target. http://youtu.be/DujfpXOKUp8?t=13m8s
@@ -979,14 +977,14 @@ class Component {
// Proceed only if the touchmove/leave/cancel event didn't happen
if (couldBeTap === true) {
// Measure how long the touch lasted
- touchTime = new Date().getTime() - touchStart;
+ const touchTime = new Date().getTime() - touchStart;
// Make sure the touch was less than the threshold to be considered a tap
if (touchTime < touchTimeThreshold) {
event.preventDefault(); // Don't let browser turn this into a click
this.trigger('tap');
// It may be good to copy the touchend event object and change the
// type to tap, if the other event properties aren't exact after
- // vjs.fixEvent runs (e.g. event.target)
+ // Lib.fixEvent runs (e.g. event.target)
}
}
});
@@ -1016,16 +1014,15 @@ class Component {
* want touch events to act differently.
*/
enableTouchActivity() {
- var report, touchHolding, touchEnd;
-
// Don't continue if the root player doesn't support reporting user activity
if (!this.player().reportUserActivity) {
return;
}
// listener for reporting that the user is active
- report = Lib.bind(this.player(), this.player().reportUserActivity);
+ const report = Lib.bind(this.player(), this.player().reportUserActivity);
+ let touchHolding;
this.on('touchstart', function() {
report();
// For as long as the they are touching the device or have their mouse down,
@@ -1036,7 +1033,7 @@ class Component {
touchHolding = this.setInterval(report, 250);
});
- touchEnd = function(event) {
+ const touchEnd = function(event) {
report();
// stop the interval that maintains activity if the touch is holding
this.clearInterval(touchHolding);
@@ -1063,7 +1060,7 @@ class Component {
this.clearTimeout(timeoutId);
};
- disposeFn.guid = 'vjs-timeout-'+ timeoutId;
+ disposeFn.guid = `vjs-timeout-${timeoutId}`;
this.on('dispose', disposeFn);
@@ -1080,7 +1077,7 @@ class Component {
clearTimeout(timeoutId);
var disposeFn = function(){};
- disposeFn.guid = 'vjs-timeout-'+ timeoutId;
+ disposeFn.guid = `vjs-timeout-${timeoutId}`;
this.off('dispose', disposeFn);
@@ -1102,7 +1099,7 @@ class Component {
this.clearInterval(intervalId);
};
- disposeFn.guid = 'vjs-interval-'+ intervalId;
+ disposeFn.guid = `vjs-interval-${intervalId}`;
this.on('dispose', disposeFn);
@@ -1118,7 +1115,7 @@ class Component {
clearInterval(intervalId);
var disposeFn = function(){};
- disposeFn.guid = 'vjs-interval-'+ intervalId;
+ disposeFn.guid = `vjs-interval-${intervalId}`;
this.off('dispose', disposeFn);
@@ -1140,7 +1137,7 @@ class Component {
}
if (window && window.videojs && window.videojs[name]) {
- Lib.log.warn('The '+name+' component was added to the videojs object when it should be registered using videojs.registerComponent(name, component)');
+ Lib.log.warn(`The ${name} component was added to the videojs object when it should be registered using videojs.registerComponent(name, component)`);
return window.videojs[name];
}
}
diff --git a/src/js/control-bar/control-bar.js b/src/js/control-bar/control-bar.js
index 80f41f1ff..ebfc9d566 100644
--- a/src/js/control-bar/control-bar.js
+++ b/src/js/control-bar/control-bar.js
@@ -3,10 +3,10 @@ import * as Lib from '../lib.js';
// Required children
import PlayToggle from './play-toggle.js';
-import CurrentTimeDisplay from './current-time-display.js';
-import DurationDisplay from './duration-display.js';
-import TimeDivider from './time-divider.js';
-import RemainingTimeDisplay from './remaining-time-display.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';
@@ -17,14 +17,15 @@ import ChaptersButton from './text-track-controls/chapters-button.js';
import SubtitlesButton from './text-track-controls/subtitles-button.js';
import CaptionsButton from './text-track-controls/captions-button.js';
import PlaybackRateMenuButton from './playback-rate-menu/playback-rate-menu-button.js';
+import CustomControlSpacer from './spacer-controls/custom-control-spacer.js';
/**
* Container of main controls
- * @param {vjs.Player|Object} player
+ * @param {Player|Object} player
* @param {Object=} options
* @class
* @constructor
- * @extends vjs.Component
+ * @extends Component
*/
class ControlBar extends Component {
createEl() {
@@ -36,24 +37,25 @@ class ControlBar extends Component {
ControlBar.prototype.options_ = {
loadEvent: 'play',
- children: {
- 'playToggle': {},
- 'currentTimeDisplay': {},
- 'timeDivider': {},
- 'durationDisplay': {},
- 'remainingTimeDisplay': {},
- 'liveDisplay': {},
- 'progressControl': {},
- 'fullscreenToggle': {},
- 'volumeControl': {},
- 'muteToggle': {},
- // 'volumeMenuButton': {},
- 'playbackRateMenuButton': {},
- 'subtitlesButton': {},
- 'captionsButton': {},
- 'chaptersButton': {}
- }
+ children: [
+ 'playToggle',
+ 'currentTimeDisplay',
+ 'timeDivider',
+ 'durationDisplay',
+ 'progressControl',
+ 'liveDisplay',
+ 'remainingTimeDisplay',
+ 'customControlSpacer',
+ 'playbackRateMenuButton',
+ 'muteToggle',
+ 'volumeControl',
+ 'chaptersButton',
+ 'subtitlesButton',
+ 'captionsButton',
+ 'volumeMenuButton',
+ 'fullscreenToggle'
+ ]
};
Component.registerComponent('ControlBar', ControlBar);
-export default ControlBar;
\ No newline at end of file
+export default ControlBar;
diff --git a/src/js/control-bar/fullscreen-toggle.js b/src/js/control-bar/fullscreen-toggle.js
index 6a63276fa..ce3fe89cb 100644
--- a/src/js/control-bar/fullscreen-toggle.js
+++ b/src/js/control-bar/fullscreen-toggle.js
@@ -2,7 +2,7 @@ import Button from '../button';
/**
* Toggle fullscreen video
- * @param {vjs.Player|Object} player
+ * @param {Player|Object} player
* @param {Object=} options
* @class
* @extends vjs.Button
@@ -10,10 +10,10 @@ import Button from '../button';
class FullscreenToggle extends Button {
buildCSSClass() {
- return 'vjs-fullscreen-control ' + super.buildCSSClass();
+ return `vjs-fullscreen-control ${super.buildCSSClass()}`;
}
- onClick() {
+ handleClick() {
if (!this.player_.isFullscreen()) {
this.player_.requestFullscreen();
this.controlText_.innerHTML = this.localize('Non-Fullscreen');
diff --git a/src/js/control-bar/live-display.js b/src/js/control-bar/live-display.js
index 46a85ea62..69464fd42 100644
--- a/src/js/control-bar/live-display.js
+++ b/src/js/control-bar/live-display.js
@@ -4,7 +4,7 @@ import * as Lib from '../lib';
/**
* Displays the live indicator
* TODO - Future make it click to snap to live
- * @param {vjs.Player|Object} player
+ * @param {Player|Object} player
* @param {Object=} options
* @constructor
*/
@@ -12,12 +12,12 @@ class LiveDisplay extends Component {
createEl() {
var el = super.createEl('div', {
- className: 'vjs-live-controls vjs-control'
+ className: 'vjs-live-control vjs-control'
});
this.contentEl_ = Lib.createEl('div', {
className: 'vjs-live-display',
- innerHTML: '' + this.localize('Stream Type') + ' ' + this.localize('LIVE'),
+ innerHTML: `${this.localize('Stream Type')} ${this.localize('LIVE')}`,
'aria-live': 'off'
});
diff --git a/src/js/control-bar/mute-toggle.js b/src/js/control-bar/mute-toggle.js
index b49dbb91f..a84138a9b 100644
--- a/src/js/control-bar/mute-toggle.js
+++ b/src/js/control-bar/mute-toggle.js
@@ -5,7 +5,7 @@ import * as Lib from '../lib';
/**
* A button component for muting the audio
*
- * @param {vjs.Player|Object} player
+ * @param {Player|Object} player
* @param {Object=} options
* @constructor
*/
@@ -32,12 +32,16 @@ class MuteToggle extends Button {
createEl() {
return super.createEl('div', {
- className: 'vjs-mute-control vjs-control',
- innerHTML: '' + this.localize('Mute') + '
'
+ className: this.buildCSSClass(),
+ innerHTML: `${this.localize('Mute')}
`
});
}
- onClick() {
+ buildCSSClass() {
+ return `vjs-mute-control ${super.buildCSSClass()}`;
+ }
+
+ handleClick() {
this.player_.muted( this.player_.muted() ? false : true );
}
@@ -64,9 +68,9 @@ class MuteToggle extends Button {
/* TODO improve muted icon classes */
for (var i = 0; i < 4; i++) {
- Lib.removeClass(this.el_, 'vjs-vol-'+i);
+ Lib.removeClass(this.el_, `vjs-vol-${i}`);
}
- Lib.addClass(this.el_, 'vjs-vol-'+level);
+ Lib.addClass(this.el_, `vjs-vol-${level}`);
}
}
diff --git a/src/js/control-bar/play-toggle.js b/src/js/control-bar/play-toggle.js
index 796c12391..c3de4ce7d 100644
--- a/src/js/control-bar/play-toggle.js
+++ b/src/js/control-bar/play-toggle.js
@@ -3,7 +3,7 @@ import * as Lib from '../lib';
/**
* Button to toggle between play and pause
- * @param {vjs.Player|Object} player
+ * @param {Player|Object} player
* @param {Object=} options
* @class
* @constructor
@@ -13,16 +13,16 @@ class PlayToggle extends Button {
constructor(player, options){
super(player, options);
- this.on(player, 'play', this.onPlay);
- this.on(player, 'pause', this.onPause);
+ this.on(player, 'play', this.handlePlay);
+ this.on(player, 'pause', this.handlePause);
}
buildCSSClass() {
- return 'vjs-play-control ' + super.buildCSSClass();
+ return `vjs-play-control ${super.buildCSSClass()}`;
}
- // OnClick - Toggle between play and pause
- onClick() {
+ // handleClick - Toggle between play and pause
+ handleClick() {
if (this.player_.paused()) {
this.player_.play();
} else {
@@ -30,15 +30,15 @@ class PlayToggle extends Button {
}
}
- // OnPlay - Add the vjs-playing class to the element so it can change appearance
- onPlay() {
+ // handlePlay - Add the vjs-playing class to the element so it can change appearance
+ handlePlay() {
this.removeClass('vjs-paused');
this.addClass('vjs-playing');
this.el_.children[0].children[0].innerHTML = this.localize('Pause'); // change the button text to "Pause"
}
- // OnPause - Add the vjs-paused class to the element so it can change appearance
- onPause() {
+ // handlePause - Add the vjs-paused class to the element so it can change appearance
+ handlePause() {
this.removeClass('vjs-playing');
this.addClass('vjs-paused');
this.el_.children[0].children[0].innerHTML = this.localize('Play'); // change the button text to "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 3802e9149..e7b28d1b5 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
@@ -6,7 +6,7 @@ import * as Lib from '../../lib.js';
/**
* The component for controlling the playback rate
*
- * @param {vjs.Player|Object} player
+ * @param {Player|Object} player
* @param {Object=} options
* @constructor
*/
@@ -56,7 +56,7 @@ class PlaybackRateMenuButton extends MenuButton {
this.el().setAttribute('aria-valuenow', this.player().playbackRate());
}
- onClick() {
+ handleClick() {
// select next rate option
let currentRate = this.player().playbackRate();
let rates = this.player().options()['playbackRates'];
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 572203f02..65695dcd1 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
@@ -22,8 +22,8 @@ class PlaybackRateMenuItem extends MenuItem {
this.on(player, 'ratechange', this.update);
}
- onClick() {
- super.onClick();
+ handleClick() {
+ super.handleClick();
this.player().playbackRate(this.rate);
}
@@ -36,4 +36,4 @@ class PlaybackRateMenuItem extends MenuItem {
PlaybackRateMenuItem.prototype.contentElType = 'button';
MenuItem.registerComponent('PlaybackRateMenuItem', PlaybackRateMenuItem);
-export default PlaybackRateMenuItem;
\ No newline at end of file
+export default PlaybackRateMenuItem;
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 589c2003e..48298f519 100644
--- a/src/js/control-bar/progress-control/load-progress-bar.js
+++ b/src/js/control-bar/progress-control/load-progress-bar.js
@@ -4,7 +4,7 @@ import * as Lib from '../../lib.js';
/**
* Shows load progress
*
- * @param {vjs.Player|Object} player
+ * @param {Player|Object} player
* @param {Object=} options
* @constructor
*/
@@ -18,7 +18,7 @@ class LoadProgressBar extends Component {
createEl() {
return super.createEl('div', {
className: 'vjs-load-progress',
- innerHTML: '' + this.localize('Loaded') + ' : 0% '
+ innerHTML: `${this.localize('Loaded')} : 0% `
});
}
@@ -61,4 +61,4 @@ class LoadProgressBar extends Component {
}
Component.registerComponent('LoadProgressBar', LoadProgressBar);
-export default LoadProgressBar;
\ No newline at end of file
+export default LoadProgressBar;
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 f78c7a385..aaf656bef 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,7 @@ import Component from '../../component.js';
/**
* Shows play progress
*
- * @param {vjs.Player|Object} player
+ * @param {Player|Object} player
* @param {Object=} options
* @constructor
*/
@@ -12,11 +12,11 @@ class PlayProgressBar extends Component {
createEl() {
return super.createEl('div', {
className: 'vjs-play-progress',
- innerHTML: '' + this.localize('Progress') + ' : 0% '
+ innerHTML: `${this.localize('Progress')} : 0% `
});
}
}
Component.registerComponent('PlayProgressBar', PlayProgressBar);
-export default PlayProgressBar;
\ No newline at end of file
+export default PlayProgressBar;
diff --git a/src/js/control-bar/progress-control/progress-control.js b/src/js/control-bar/progress-control/progress-control.js
index 7afe41e23..1834d60bc 100644
--- a/src/js/control-bar/progress-control/progress-control.js
+++ b/src/js/control-bar/progress-control/progress-control.js
@@ -5,7 +5,7 @@ import SeekBar from './seek-bar.js';
* The Progress Control component contains the seek bar, load progress,
* and play progress
*
- * @param {vjs.Player|Object} player
+ * @param {Player|Object} player
* @param {Object=} options
* @constructor
*/
diff --git a/src/js/control-bar/progress-control/seek-bar.js b/src/js/control-bar/progress-control/seek-bar.js
index 6fcfed873..0c18642e8 100644
--- a/src/js/control-bar/progress-control/seek-bar.js
+++ b/src/js/control-bar/progress-control/seek-bar.js
@@ -7,7 +7,7 @@ import * as Lib from '../../lib.js';
/**
* Seek Bar and holder for the progress bars
*
- * @param {vjs.Player|Object} player
+ * @param {Player|Object} player
* @param {Object=} options
* @constructor
*/
@@ -28,7 +28,7 @@ class SeekBar extends Slider {
updateARIAAttributes() {
// Allows for smooth scrubbing, when player can't keep up.
- let time = (this.player_.scrubbing) ? this.player_.getCache().currentTime : this.player_.currentTime();
+ let time = (this.player_.scrubbing()) ? this.player_.getCache().currentTime : this.player_.currentTime();
this.el_.setAttribute('aria-valuenow', Lib.round(this.getPercent()*100, 2)); // machine readable value of progress bar (percentage complete)
this.el_.setAttribute('aria-valuetext', Lib.formatTime(time, this.player_.duration())); // human readable value of progress bar (time complete)
}
@@ -37,17 +37,16 @@ class SeekBar extends Slider {
return this.player_.currentTime() / this.player_.duration();
}
- onMouseDown(event) {
- super.onMouseDown(event);
+ handleMouseDown(event) {
+ super.handleMouseDown(event);
- this.player_.scrubbing = true;
- this.player_.addClass('vjs-scrubbing');
+ this.player_.scrubbing(true);
this.videoWasPlaying = !this.player_.paused();
this.player_.pause();
}
- onMouseMove(event) {
+ handleMouseMove(event) {
let newTime = this.calculateDistance(event) * this.player_.duration();
// Don't let video end while scrubbing.
@@ -57,11 +56,10 @@ class SeekBar extends Slider {
this.player_.currentTime(newTime);
}
- onMouseUp(event) {
- super.onMouseUp(event);
+ handleMouseUp(event) {
+ super.handleMouseUp(event);
- this.player_.scrubbing = false;
- this.player_.removeClass('vjs-scrubbing');
+ this.player_.scrubbing(false);
if (this.videoWasPlaying) {
this.player_.play();
}
diff --git a/src/js/control-bar/progress-control/seek-handle.js b/src/js/control-bar/progress-control/seek-handle.js
index ff7c4ae3e..bccfff7b5 100644
--- a/src/js/control-bar/progress-control/seek-handle.js
+++ b/src/js/control-bar/progress-control/seek-handle.js
@@ -5,7 +5,7 @@ import * as Lib from '../../lib.js';
* The Seek Handle shows the current position of the playhead during playback,
* and can be dragged to adjust the playhead.
*
- * @param {vjs.Player|Object} player
+ * @param {Player|Object} player
* @param {Object=} options
* @constructor
*/
@@ -18,7 +18,7 @@ class SeekHandle extends SliderHandle {
/** @inheritDoc */
createEl() {
- return super.createEl.call('div', {
+ return super.createEl('div', {
className: 'vjs-seek-handle',
'aria-live': 'off'
});
@@ -26,7 +26,7 @@ class SeekHandle extends SliderHandle {
updateContent() {
let time = (this.player_.scrubbing) ? this.player_.getCache().currentTime : this.player_.currentTime();
- this.el_.innerHTML = '' + Lib.formatTime(time, this.player_.duration()) + ' ';
+ this.el_.innerHTML = `${Lib.formatTime(time, this.player_.duration())} `;
}
}
@@ -40,4 +40,4 @@ class SeekHandle extends SliderHandle {
SeekHandle.prototype.defaultValue = '00:00';
SliderHandle.registerComponent('SeekHandle', SeekHandle);
-export default SeekHandle;
\ No newline at end of file
+export default SeekHandle;
diff --git a/src/js/control-bar/spacer-controls/custom-control-spacer.js b/src/js/control-bar/spacer-controls/custom-control-spacer.js
new file mode 100644
index 000000000..d2475ae4d
--- /dev/null
+++ b/src/js/control-bar/spacer-controls/custom-control-spacer.js
@@ -0,0 +1,23 @@
+import Spacer from './spacer.js';
+
+/**
+ * Spacer specifically meant to be used as an insertion point for new plugins, etc.
+ *
+ * @param {Player|Object} player
+ * @param {Obect=} options
+ */
+class CustomControlSpacer extends Spacer {
+ buildCSSClass() {
+ return `vjs-custom-control-spacer ${super.buildCSSClass()}`;
+ }
+
+ createEl() {
+ return super.createEl({
+ className: this.buildCSSClass()
+ });
+ }
+}
+
+Spacer.registerComponent('CustomControlSpacer', CustomControlSpacer);
+
+export default CustomControlSpacer;
diff --git a/src/js/control-bar/spacer-controls/spacer.js b/src/js/control-bar/spacer-controls/spacer.js
new file mode 100644
index 000000000..86bcc3acc
--- /dev/null
+++ b/src/js/control-bar/spacer-controls/spacer.js
@@ -0,0 +1,24 @@
+import Component from '../../component.js';
+
+/**
+ * Just an empty spacer element that can be used as an append point for plugins, etc.
+ * Also can be used to create space between elements when necessary.
+ *
+ * @param {Player|Object} player
+ * @param {Object=} options
+ */
+class Spacer extends Component {
+ buildCSSClass() {
+ return `vjs-spacer ${super.buildCSSClass()}`;
+ }
+
+ createEl(props) {
+ return super.createEl('div', {
+ className: this.buildCSSClass()
+ });
+ }
+}
+
+Component.registerComponent('Spacer', Spacer);
+
+export default Spacer;
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 037c6c4cb..093fb141f 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
@@ -15,11 +15,11 @@ class CaptionSettingsMenuItem extends TextTrackMenuItem {
this.addClass('vjs-texttrack-settings');
}
- onClick() {
+ handleClick() {
this.player().getChild('textTrackSettings').show();
}
}
TextTrackMenuItem.registerComponent('CaptionSettingsMenuItem', CaptionSettingsMenuItem);
-export default CaptionSettingsMenuItem;
\ No newline at end of file
+export default CaptionSettingsMenuItem;
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 a7a397b0d..faeff7ba6 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
@@ -21,8 +21,8 @@ class ChaptersTrackMenuItem extends MenuItem {
track.addEventListener('cuechange', Lib.bind(this, this.update));
}
- onClick() {
- super.onClick();
+ handleClick() {
+ super.handleClick();
this.player_.currentTime(this.cue.startTime);
this.update(this.cue.startTime);
}
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 41a74e262..5ce1d002f 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
@@ -58,11 +58,11 @@ class TextTrackMenuItem extends MenuItem {
}
}
- onClick(event) {
+ handleClick(event) {
let kind = this.track['kind'];
let tracks = this.player_.textTracks();
- super.onClick(event);
+ super.handleClick(event);
if (!tracks) return;
@@ -88,4 +88,4 @@ class TextTrackMenuItem extends MenuItem {
}
MenuItem.registerComponent('TextTrackMenuItem', TextTrackMenuItem);
-export default TextTrackMenuItem;
\ No newline at end of file
+export default TextTrackMenuItem;
diff --git a/src/js/control-bar/current-time-display.js b/src/js/control-bar/time-controls/current-time-display.js
similarity index 70%
rename from src/js/control-bar/current-time-display.js
rename to src/js/control-bar/time-controls/current-time-display.js
index 72786f31a..741b01166 100644
--- a/src/js/control-bar/current-time-display.js
+++ b/src/js/control-bar/time-controls/current-time-display.js
@@ -1,9 +1,9 @@
-import Component from '../component.js';
-import * as Lib from '../lib.js';
+import Component from '../../component.js';
+import * as Lib from '../../lib.js';
/**
* Displays the current time
- * @param {vjs.Player|Object} player
+ * @param {Player|Object} player
* @param {Object=} options
* @constructor
*/
@@ -17,7 +17,7 @@ class CurrentTimeDisplay extends Component {
createEl() {
let el = super.createEl('div', {
- className: 'vjs-current-time vjs-time-controls vjs-control'
+ className: 'vjs-current-time vjs-time-control vjs-control'
});
this.contentEl_ = Lib.createEl('div', {
@@ -33,7 +33,9 @@ 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();
- this.contentEl_.innerHTML = '' + this.localize('Current Time') + ' ' + Lib.formatTime(time, this.player_.duration());
+ let localizedText = this.localize('Current Time');
+ let formattedTime = Lib.formatTime(time, this.player_.duration());
+ this.contentEl_.innerHTML = `${localizedText} ${formattedTime}`;
}
}
diff --git a/src/js/control-bar/duration-display.js b/src/js/control-bar/time-controls/duration-display.js
similarity index 65%
rename from src/js/control-bar/duration-display.js
rename to src/js/control-bar/time-controls/duration-display.js
index ade6b7b2c..7daffaf04 100644
--- a/src/js/control-bar/duration-display.js
+++ b/src/js/control-bar/time-controls/duration-display.js
@@ -1,9 +1,9 @@
-import Component from '../component.js';
-import * as Lib from '../lib.js';
+import Component from '../../component.js';
+import * as Lib from '../../lib.js';
/**
* Displays the duration
- * @param {vjs.Player|Object} player
+ * @param {Player|Object} player
* @param {Object=} options
* @constructor
*/
@@ -22,12 +22,12 @@ class DurationDisplay extends Component {
createEl() {
let el = super.createEl('div', {
- className: 'vjs-duration vjs-time-controls vjs-control'
+ className: 'vjs-duration vjs-time-control vjs-control'
});
this.contentEl_ = Lib.createEl('div', {
className: 'vjs-duration-display',
- innerHTML: '' + this.localize('Duration Time') + ' ' + '0:00', // label the duration time for screen reader users
+ innerHTML: `${this.localize('Duration Time')} 0:00`, // label the duration time for screen reader users
'aria-live': 'off' // tell screen readers not to automatically read the time as it changes
});
@@ -38,7 +38,9 @@ class DurationDisplay extends Component {
updateContent() {
let duration = this.player_.duration();
if (duration) {
- this.contentEl_.innerHTML = '' + this.localize('Duration Time') + ' ' + Lib.formatTime(duration); // label the duration time for screen reader users
+ let localizedText = this.localize('Duration Time');
+ let formattedTime = Lib.formatTime(duration);
+ this.contentEl_.innerHTML = `${localizedText} ${formattedTime}`; // label the duration time for screen reader users
}
}
diff --git a/src/js/control-bar/remaining-time-display.js b/src/js/control-bar/time-controls/remaining-time-display.js
similarity index 65%
rename from src/js/control-bar/remaining-time-display.js
rename to src/js/control-bar/time-controls/remaining-time-display.js
index d3842aefb..9e6e1f436 100644
--- a/src/js/control-bar/remaining-time-display.js
+++ b/src/js/control-bar/time-controls/remaining-time-display.js
@@ -1,5 +1,5 @@
-import Component from '../component.js';
-import * as Lib from '../lib';
+import Component from '../../component.js';
+import * as Lib from '../../lib';
/**
* Displays the time left in the video
@@ -17,12 +17,12 @@ class RemainingTimeDisplay extends Component {
createEl() {
let el = super.createEl('div', {
- className: 'vjs-remaining-time vjs-time-controls vjs-control'
+ className: 'vjs-remaining-time vjs-time-control vjs-control'
});
this.contentEl_ = Lib.createEl('div', {
className: 'vjs-remaining-time-display',
- innerHTML: '' + this.localize('Remaining Time') + ' ' + '-0:00', // label the remaining time for screen reader users
+ innerHTML: `${this.localize('Remaining Time')} -0:00`, // label the remaining time for screen reader users
'aria-live': 'off' // tell screen readers not to automatically read the time as it changes
});
@@ -32,7 +32,9 @@ class RemainingTimeDisplay extends Component {
updateContent() {
if (this.player_.duration()) {
- this.contentEl_.innerHTML = '' + this.localize('Remaining Time') + ' ' + '-'+ Lib.formatTime(this.player_.remainingTime());
+ const localizedText = this.localize('Remaining Time');
+ const formattedTime = Lib.formatTime(this.player_.remainingTime());
+ this.contentEl_.innerHTML = `${localizedText} -${formattedTime}`;
}
// Allows for smooth scrubbing, when player can't keep up.
diff --git a/src/js/control-bar/time-divider.js b/src/js/control-bar/time-controls/time-divider.js
similarity index 70%
rename from src/js/control-bar/time-divider.js
rename to src/js/control-bar/time-controls/time-divider.js
index e3c4996f4..46d7ce142 100644
--- a/src/js/control-bar/time-divider.js
+++ b/src/js/control-bar/time-controls/time-divider.js
@@ -1,11 +1,11 @@
-import Component from '../component.js';
+import Component from '../../component.js';
/**
* The separator between the current time and duration
*
* Can be hidden if it's not needed in the design.
*
- * @param {vjs.Player|Object} player
+ * @param {Player|Object} player
* @param {Object=} options
* @constructor
*/
@@ -13,7 +13,7 @@ class TimeDivider extends Component {
createEl() {
return super.createEl('div', {
- className: 'vjs-time-divider',
+ className: 'vjs-time-control vjs-time-divider',
innerHTML: '/
'
});
}
@@ -21,4 +21,4 @@ class TimeDivider extends Component {
}
Component.registerComponent('TimeDivider', TimeDivider);
-export default TimeDivider;
\ No newline at end of file
+export default TimeDivider;
diff --git a/src/js/control-bar/volume-control/volume-bar.js b/src/js/control-bar/volume-control/volume-bar.js
index b12d15472..cc3c56a12 100644
--- a/src/js/control-bar/volume-control/volume-bar.js
+++ b/src/js/control-bar/volume-control/volume-bar.js
@@ -8,7 +8,7 @@ import VolumeLevel from './volume-level.js';
/**
* The bar that contains the volume level and can be clicked on to adjust the level
*
- * @param {vjs.Player|Object} player
+ * @param {Player|Object} player
* @param {Object=} options
* @constructor
*/
@@ -27,7 +27,7 @@ class VolumeBar extends Slider {
});
}
- onMouseMove(event) {
+ handleMouseMove(event) {
if (this.player_.muted()) {
this.player_.muted(false);
}
diff --git a/src/js/control-bar/volume-control/volume-control.js b/src/js/control-bar/volume-control/volume-control.js
index bfcd2cb39..de507925c 100644
--- a/src/js/control-bar/volume-control/volume-control.js
+++ b/src/js/control-bar/volume-control/volume-control.js
@@ -7,7 +7,7 @@ import VolumeBar from './volume-bar.js';
/**
* The component for controlling the volume level
*
- * @param {vjs.Player|Object} player
+ * @param {Player|Object} player
* @param {Object=} options
* @constructor
*/
diff --git a/src/js/control-bar/volume-control/volume-handle.js b/src/js/control-bar/volume-control/volume-handle.js
index 9382574fb..7dbd61276 100644
--- a/src/js/control-bar/volume-control/volume-handle.js
+++ b/src/js/control-bar/volume-control/volume-handle.js
@@ -3,7 +3,7 @@ import SliderHandle from '../../slider/slider-handle.js';
/**
* The volume handle can be dragged to adjust the volume level
*
- * @param {vjs.Player|Object} player
+ * @param {Player|Object} player
* @param {Object=} options
* @constructor
*/
@@ -21,4 +21,4 @@ class VolumeHandle extends SliderHandle {
VolumeHandle.prototype.defaultValue = '00:00';
SliderHandle.registerComponent('VolumeHandle', VolumeHandle);
-export default VolumeHandle;
\ No newline at end of file
+export default VolumeHandle;
diff --git a/src/js/control-bar/volume-control/volume-level.js b/src/js/control-bar/volume-control/volume-level.js
index de25e95d3..8de8f9210 100644
--- a/src/js/control-bar/volume-control/volume-level.js
+++ b/src/js/control-bar/volume-control/volume-level.js
@@ -3,7 +3,7 @@ import Component from '../../component.js';
/**
* Shows volume level
*
- * @param {vjs.Player|Object} player
+ * @param {Player|Object} player
* @param {Object=} options
* @constructor
*/
@@ -19,4 +19,4 @@ class VolumeLevel extends Component {
}
Component.registerComponent('VolumeLevel', VolumeLevel);
-export default VolumeLevel;
\ No newline at end of file
+export default VolumeLevel;
diff --git a/src/js/control-bar/volume-menu-button.js b/src/js/control-bar/volume-menu-button.js
index 3d67b2dcb..590bedec4 100644
--- a/src/js/control-bar/volume-menu-button.js
+++ b/src/js/control-bar/volume-menu-button.js
@@ -35,7 +35,13 @@ class VolumeMenuButton extends MenuButton {
let menu = new Menu(this.player_, {
contentElType: 'div'
});
- let vc = new VolumeBar(this.player_, this.options_['volumeBar']);
+
+ // The volumeBar is vertical by default in the base theme when used with a VolumeMenuButton
+ var options = this.options_['volumeBar'] || {};
+ options['vertical'] = options['vertical'] || true;
+
+ let vc = new VolumeBar(this.player_, options);
+
vc.on('focus', function() {
menu.lockShowing();
});
@@ -46,15 +52,15 @@ class VolumeMenuButton extends MenuButton {
return menu;
}
- onClick() {
- MuteToggle.prototype.onClick.call(this);
- super.onClick();
+ handleClick() {
+ MuteToggle.prototype.handleClick.call(this);
+ super.handleClick();
}
createEl() {
return super.createEl('div', {
- className: 'vjs-volume-menu-button vjs-menu-button vjs-control',
- innerHTML: '' + this.localize('Mute') + '
'
+ className: 'vjs-volume-menu-button vjs-menu-button vjs-control vjs-button',
+ innerHTML: `${this.localize('Mute')}
`
});
}
diff --git a/src/js/core-object.js b/src/js/core-object.js
index 0e942efc1..93cb76877 100644
--- a/src/js/core-object.js
+++ b/src/js/core-object.js
@@ -66,11 +66,10 @@ var CoreObject = function(){};
*
* @param {Object} props Functions and properties to be applied to the
* new object's prototype
- * @return {vjs.CoreObject} An object that inherits from CoreObject
+ * @return {CoreObject} An object that inherits from CoreObject
* @this {*}
*/
-CoreObject.extend = function(props){
- props = props || {};
+CoreObject.extend = function(props={}){
// Set up the constructor using the supplied init method
// or using the init of the parent object
// Make sure to check the unobfuscated version for external libs
@@ -114,7 +113,7 @@ CoreObject.extend = function(props){
*
* var myAnimal = Animal.create();
*
- * @return {vjs.CoreObject} An instance of a CoreObject subclass
+ * @return {CoreObject} An instance of a CoreObject subclass
* @this {*}
*/
CoreObject.create = function(){
diff --git a/src/js/core.js b/src/js/core.js
index ae1d9e663..8774f14fc 100644
--- a/src/js/core.js
+++ b/src/js/core.js
@@ -23,7 +23,7 @@ import document from 'global/document';
* @param {String|Element} id Video element or video element ID
* @param {Object=} options Optional options object for config/settings
* @param {Function=} ready Optional ready callback
- * @return {vjs.Player} A player instance
+ * @return {Player} A player instance
* @namespace
*/
var videojs = function(id, options, ready){
@@ -43,7 +43,7 @@ var videojs = function(id, options, ready){
// If options or ready funtion are passed, warn
if (options) {
- Lib.log.warn('Player "' + id + '" is already initialised. Options will not be applied.');
+ Lib.log.warn(`Player "${id}" is already initialised. Options will not be applied.`);
}
if (ready) {
@@ -88,14 +88,14 @@ videojs['VERSION'] = '__VERSION__';
// Set CDN Version of swf
// The added (+) blocks the replace from changing this _VERSION_NO_PATCH_ string
if (videojs.CDN_VERSION !== '__VERSION_'+'NO_PATCH__') {
- Options['flash']['swf'] = videojs.ACCESS_PROTOCOL + 'vjs.zencdn.net/'+videojs.CDN_VERSION+'/video-js.swf';
+ Options['flash']['swf'] = `${videojs.ACCESS_PROTOCOL}vjs.zencdn.net/${videojs.CDN_VERSION}/video-js.swf`;
}
/**
* Utility function for adding languages to the default options. Useful for
* amending multiple language support at runtime.
*
- * Example: vjs.addLanguage('es', {'Hello':'Hola'});
+ * Example: videojs.addLanguage('es', {'Hello':'Hola'});
*
* @param {String} code The language code or dictionary property
* @param {Object} data The data values to be translated
diff --git a/src/js/error-display.js b/src/js/error-display.js
index 597fcfdbf..bfb3c24e8 100644
--- a/src/js/error-display.js
+++ b/src/js/error-display.js
@@ -3,7 +3,7 @@ import * as Lib from './lib';
/**
* Display that an error has occurred making the video unplayable
- * @param {vjs.Player|Object} player
+ * @param {Player|Object} player
* @param {Object=} options
* @constructor
*/
diff --git a/src/js/event-emitter.js b/src/js/event-emitter.js
index 1a33353a7..581951b8a 100644
--- a/src/js/event-emitter.js
+++ b/src/js/event-emitter.js
@@ -6,7 +6,7 @@ var EventEmitter = function() {};
EventEmitter.prototype.allowedEvents_ = {};
EventEmitter.prototype.on = function(type, fn) {
- // Remove the addEventListener alias before calling vjs.on
+ // Remove the addEventListener alias before calling Events.on
// so we don't get into an infinite type loop
let ael = this.addEventListener;
this.addEventListener = Function.prototype;
diff --git a/src/js/events.js b/src/js/events.js
index 814d6476c..507822b15 100644
--- a/src/js/events.js
+++ b/src/js/events.js
@@ -62,11 +62,9 @@ var fixEvent = function(event) {
old.preventDefault();
}
event.returnValue = false;
- event.isDefaultPrevented = returnTrue;
event.defaultPrevented = true;
};
- event.isDefaultPrevented = returnFalse;
event.defaultPrevented = false;
// Stop the event from bubbling
@@ -325,25 +323,6 @@ var trigger = function(elem, event) {
// Inform the triggerer if the default was prevented by returning false
return !event.defaultPrevented;
- /* Original version of js ninja events wasn't complete.
- * We've since updated to the latest version, but keeping this around
- * for now just in case.
- */
- // // Added in addition to book. Book code was broke.
- // event = typeof event === 'object' ?
- // event[vjs.expando] ?
- // event :
- // new vjs.Event(type, event) :
- // new vjs.Event(type);
-
- // event.type = type;
- // if (handler) {
- // handler.call(elem, event);
- // }
-
- // // Clean up the event in case it is being reused
- // event.result = undefined;
- // event.target = elem;
};
/**
diff --git a/src/js/extends.js b/src/js/extends.js
new file mode 100644
index 000000000..a68ab0b12
--- /dev/null
+++ b/src/js/extends.js
@@ -0,0 +1,71 @@
+import * as Lib from './lib';
+
+/**
+ * A combination of node inherits and babel's inherits (after transpile).
+ * Both work the same but node adds `super_` to the subClass
+ * and Bable adds the superClass as __proto__. Both seem useful.
+ */
+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);
+ }
+
+ subClass.prototype = Object.create(superClass && superClass.prototype, {
+ constructor: {
+ value: subClass,
+ enumerable: false,
+ writable: true,
+ configurable: true
+ }
+ });
+
+ if (superClass) {
+ // node
+ subClass.super_ = superClass;
+ }
+};
+
+/**
+ * Function for subclassing using the same inheritance that
+ * videojs uses internally
+ *
+ * ```
+ * var Button = videojs.getComponent('Button');
+ *
+ * var MyButton = videojs.extends(Button, {
+ * constructor: function(player, options) {
+ * Button.call(this, player, options);
+ * },
+ *
+ * onClick: function() {
+ * // doSomething
+ * }
+ * });
+ * ```
+ */
+const extendsFn = function(superClass, subClassMethods={}) {
+ let subClass = function() {
+ superClass.apply(this, arguments);
+ };
+ let methods = {};
+
+ if (subClassMethods.constructor !== Object.prototype.constructor) {
+ subClass = subClassMethods.constructor;
+ methods = subClassMethods;
+ } else if (typeof subClassMethods === 'function') {
+ subClass = subClassMethods;
+ }
+
+ _inherits(subClass, superClass);
+
+ // Extend subObj's prototype with functions and other properties from props
+ for (var name in methods) {
+ if (methods.hasOwnProperty(name)) {
+ subClass.prototype[name] = methods[name];
+ }
+ }
+
+ return subClass;
+};
+
+export default extendsFn;
diff --git a/src/js/fullscreen-api.js b/src/js/fullscreen-api.js
index 84976c107..c1de7332b 100644
--- a/src/js/fullscreen-api.js
+++ b/src/js/fullscreen-api.js
@@ -5,7 +5,6 @@ import document from 'global/document';
* @type {Object|undefined}
* @private
*/
-// vjs.browser.fullscreenAPI;
let FullscreenApi = {};
// browser API methods
@@ -71,7 +70,6 @@ for (let i = 0; i < apiMap.length; i++) {
}
// map the browser API names to the spec API names
-// or leave vjs.browser.fullscreenAPI undefined
if (browserApi) {
for (let i=0; ix'
+ innerHTML: `x `
}).firstChild.href;
}
@@ -670,7 +665,7 @@ var parseUrl = function(url) {
let div;
if (addToBody) {
div = createEl('div');
- div.innerHTML = ' ';
+ div.innerHTML = ` `;
a = div.firstChild;
// prevent the div from affecting layout
div.setAttribute('style', 'display:none; position:absolute;');
@@ -712,7 +707,7 @@ function _logType(type, args){
// convert args to an array to get array functions
let argsArray = Array.prototype.slice.call(args);
// if there's no console then don't try to output messages
- // they will still be stored in vjs.log.history
+ // they will still be stored in Lib.log.history
// 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
let noop = function(){};
diff --git a/src/js/loading-spinner.js b/src/js/loading-spinner.js
index 3f70b084f..aee2cb9c0 100644
--- a/src/js/loading-spinner.js
+++ b/src/js/loading-spinner.js
@@ -4,7 +4,7 @@ import Component from './component';
================================================================================ */
/**
* Loading spinner for waiting events
- * @param {vjs.Player|Object} player
+ * @param {Player|Object} player
* @param {Object=} options
* @class
* @constructor
diff --git a/src/js/menu/menu-button.js b/src/js/menu/menu-button.js
index 5442c84f3..5e02336b0 100644
--- a/src/js/menu/menu-button.js
+++ b/src/js/menu/menu-button.js
@@ -4,7 +4,7 @@ import * as Lib from '../lib.js';
/**
* A button class with a popup menu
- * @param {vjs.Player|Object} player
+ * @param {Player|Object} player
* @param {Object=} options
* @constructor
*/
@@ -15,7 +15,7 @@ class MenuButton extends Button {
this.update();
- this.on('keydown', this.onKeyPress);
+ this.on('keydown', this.handleKeyPress);
this.el_.setAttribute('aria-haspopup', true);
this.el_.setAttribute('role', 'button');
}
@@ -75,19 +75,19 @@ class MenuButton extends Button {
/** @inheritDoc */
buildCSSClass() {
- return this.className + ' vjs-menu-button ' + super.buildCSSClass();
+ return `${this.className} vjs-menu-button ${super.buildCSSClass()}`;
}
// Focus - Add keyboard functionality to element
// This function is not needed anymore. Instead, the keyboard functionality is handled by
// treating the button as triggering a submenu. When the button is pressed, the submenu
// appears. Pressing the button again makes the submenu disappear.
- onFocus() {}
+ handleFocus() {}
// Can't turn off list display that we turned on with focus, because list would go away.
- onBlur() {}
+ handleBlur() {}
- onClick() {
+ handleClick() {
// When you click the button it adds focus, which will show the menu indefinitely.
// So we'll remove focus when the mouse leaves the button.
// Focus is needed for tab navigation.
@@ -102,7 +102,7 @@ class MenuButton extends Button {
}
}
- onKeyPress(event) {
+ handleKeyPress(event) {
// Check for space bar (32) or enter (13) keys
if (event.which == 32 || event.which == 13) {
@@ -138,4 +138,4 @@ class MenuButton extends Button {
}
Button.registerComponent('MenuButton', MenuButton);
-export default MenuButton;
\ No newline at end of file
+export default MenuButton;
diff --git a/src/js/menu/menu-item.js b/src/js/menu/menu-item.js
index c58375525..40cd24adf 100644
--- a/src/js/menu/menu-item.js
+++ b/src/js/menu/menu-item.js
@@ -4,7 +4,7 @@ import * as Lib from '../lib.js';
/**
* The component for a menu item. ``
*
- * @param {vjs.Player|Object} player
+ * @param {Player|Object} player
* @param {Object=} options
* @class
* @constructor
@@ -27,7 +27,7 @@ class MenuItem extends Button {
/**
* Handle a click on the menu item, and set it to selected
*/
- onClick() {
+ handleClick() {
this.selected(true);
}
@@ -48,4 +48,4 @@ class MenuItem extends Button {
}
Button.registerComponent('MenuItem', MenuItem);
-export default MenuItem;
\ No newline at end of file
+export default MenuItem;
diff --git a/src/js/menu/menu.js b/src/js/menu/menu.js
index 041789db6..c9665ec06 100644
--- a/src/js/menu/menu.js
+++ b/src/js/menu/menu.js
@@ -8,7 +8,7 @@ import * as Events from '../events.js';
* The Menu component is used to build pop up menus, including subtitle and
* captions selection menus.
*
- * @param {vjs.Player|Object} player
+ * @param {Player|Object} player
* @param {Object=} options
* @class
* @constructor
diff --git a/src/js/options.js b/src/js/options.js
index c47b533b5..a19efe95b 100644
--- a/src/js/options.js
+++ b/src/js/options.js
@@ -3,8 +3,8 @@ import window from 'global/window';
let navigator = window.navigator;
/**
- * Global Player instance options, surfaced from vjs.Player.prototype.options_
- * vjs.options = vjs.Player.prototype.options_
+ * Global Player instance options, surfaced from Player.prototype.options_
+ * options = Player.prototype.options_
* All options should use string keys so they avoid
* renaming by closure compiler
* @type {Object}
diff --git a/src/js/player.js b/src/js/player.js
index 8aefa7cab..52012cab5 100644
--- a/src/js/player.js
+++ b/src/js/player.js
@@ -4,7 +4,7 @@ import * as Events from './events.js';
import FullscreenApi from './fullscreen-api.js';
import MediaError from './media-error.js';
import Options from './options.js';
-import JSON from './json.js';
+import safeParseTuple from 'safe-json-parse/tuple';
import window from 'global/window';
import document from 'global/document';
@@ -21,7 +21,7 @@ import TextTrackSettings from './tracks/text-track-settings.js';
import Html5 from './tech/html5.js';
/**
- * An instance of the `vjs.Player` class is created when any of the Video.js setup methods are used to initialize a video.
+ * An instance of the `Player` class is created when any of the Video.js setup methods are used to initialize a video.
*
* ```js
* var myPlayer = videojs('example_video_1');
@@ -38,7 +38,7 @@ import Html5 from './tech/html5.js';
* After an instance has been created it can be accessed globally using `Video('example_video_1')`.
*
* @class
- * @extends vjs.Component
+ * @extends Component
*/
class Player extends Component {
@@ -53,7 +53,7 @@ class Player extends Component {
*/
constructor(tag, options, ready){
// Make sure tag ID exists
- tag.id = tag.id || 'vjs_video_' + Lib.guid++;
+ tag.id = tag.id || `vjs_video_${Lib.guid++}`;
// Set Options
// The options argument overrides options set in the video tag
@@ -76,6 +76,17 @@ class Player extends Component {
// Run base component initializing with new options
super(null, options, ready);
+
+ // if the global option object was accidentally blown away by
+ // someone, bail early with an informative error
+ if (!this.options_ ||
+ !this.options_.techOrder ||
+ !this.options_.techOrder.length) {
+ throw new Error('No techOrder specified. Did you overwrite ' +
+ 'videojs.options instead of just changing the ' +
+ 'properties you want to override?');
+ }
+
this.tag = tag; // Store the original tag used to set options
// Store the tag attributes used to restore html5 element
@@ -100,7 +111,22 @@ class Player extends Component {
// May be turned back on by HTML5 tech if nativeControlsForTouch is true
tag.controls = false;
+ /**
+ * Store the internal state of scrubbing
+ * @private
+ * @return {Boolean} True if the user is scrubbing
+ */
+ this.scrubbing_ = false;
+
this.el_ = this.createEl();
+
+ // Load plugins
+ if (options['plugins']) {
+ Lib.obj.each(options['plugins'], function(key, val){
+ this[key](val);
+ }, this);
+ }
+
this.initChildren();
// Set isAudio based on whether or not an audio tag was used
@@ -118,21 +144,19 @@ class Player extends Component {
this.addClass('vjs-audio');
}
+ if (this.flexNotSupported_()) {
+ this.addClass('vjs-no-flex');
+ }
+
// TODO: Make this smarter. Toggle user state between touching/mousing
// using events, since devices can have both touch and mouse events.
- // if (vjs.TOUCH_ENABLED) {
+ // if (Lib.TOUCH_ENABLED) {
// this.addClass('vjs-touch-enabled');
// }
// Make player easily findable by ID
Player.players[this.id_] = this;
- if (options['plugins']) {
- Lib.obj.each(options['plugins'], function(key, val){
- this[key](val);
- }, this);
- }
-
// When the player is first initialized, trigger activity so components
// like the control bar show themselves if needed
this.userActive_ = true;
@@ -200,7 +224,7 @@ class Player extends Component {
this.width(this.options_['width'], true); // (true) Skip resize listener on load
this.height(this.options_['height'], true);
- // vjs.insertFirst seems to cause the networkState to flicker from 3 to 2, so
+ // Lib.insertFirst seems to cause the networkState to flicker from 3 to 2, so
// keep track of the original for later so we can know if the source originally failed
tag.initNetworkState_ = tag.networkState;
@@ -217,18 +241,18 @@ class Player extends Component {
// like component.initEventListeners() that runs between el creation and
// adding children
this.el_ = el;
- this.on('loadstart', this.onLoadStart);
- this.on('waiting', this.onWaiting);
- this.on(['canplay', 'canplaythrough', 'playing', 'ended'], this.onWaitEnd);
- this.on('seeking', this.onSeeking);
- this.on('seeked', this.onSeeked);
- this.on('ended', this.onEnded);
- this.on('play', this.onPlay);
- this.on('firstplay', this.onFirstPlay);
- this.on('pause', this.onPause);
- this.on('progress', this.onProgress);
- this.on('durationchange', this.onDurationChange);
- this.on('fullscreenchange', this.onFullscreenChange);
+ this.on('loadstart', this.handleLoadStart);
+ this.on('waiting', this.handleWaiting);
+ this.on(['canplay', 'canplaythrough', 'playing', 'ended'], this.handleWaitEnd);
+ this.on('seeking', this.handleSeeking);
+ this.on('seeked', this.handleSeeked);
+ this.on('ended', this.handleEnded);
+ this.on('play', this.handlePlay);
+ this.on('firstplay', this.handleFirstPlay);
+ this.on('pause', this.handlePause);
+ this.on('progress', this.handleProgress);
+ this.on('durationchange', this.handleDurationChange);
+ this.on('fullscreenchange', this.handleFullscreenChange);
return el;
}
@@ -291,7 +315,7 @@ class Player extends Component {
* Fired when the user agent begins looking for media data
* @event loadstart
*/
- onLoadStart() {
+ handleLoadStart() {
// TODO: Update to use `emptied` event instead. See #1277.
this.removeClass('vjs-ended');
@@ -332,7 +356,7 @@ class Player extends Component {
* Fired whenever the media begins or resumes playback
* @event play
*/
- onPlay() {
+ handlePlay() {
this.removeClass('vjs-ended');
this.removeClass('vjs-paused');
this.addClass('vjs-playing');
@@ -346,7 +370,7 @@ class Player extends Component {
* Fired whenever the media begins waiting
* @event waiting
*/
- onWaiting() {
+ handleWaiting() {
this.addClass('vjs-waiting');
}
@@ -355,7 +379,7 @@ class Player extends Component {
* which is not consistent between browsers. See #1351
* @private
*/
- onWaitEnd() {
+ handleWaitEnd() {
this.removeClass('vjs-waiting');
}
@@ -363,7 +387,7 @@ class Player extends Component {
* Fired whenever the player is jumping to a new time
* @event seeking
*/
- onSeeking() {
+ handleSeeking() {
this.addClass('vjs-seeking');
}
@@ -371,7 +395,7 @@ class Player extends Component {
* Fired when the player has finished jumping to a new time
* @event seeked
*/
- onSeeked() {
+ handleSeeked() {
this.removeClass('vjs-seeking');
}
@@ -384,7 +408,7 @@ class Player extends Component {
*
* @event firstplay
*/
- onFirstPlay() {
+ handleFirstPlay() {
//If the first starttime attribute is specified
//then we will start at the given offset in seconds
if(this.options_['starttime']){
@@ -398,7 +422,8 @@ class Player extends Component {
* Fired whenever the media has been paused
* @event pause
*/
- onPause() {
+ handlePause() {
+ this.removeClass('vjs-playing');
this.addClass('vjs-paused');
}
@@ -406,7 +431,7 @@ class Player extends Component {
* Fired while the user agent is downloading media data
* @event progress
*/
- onProgress() {
+ handleProgress() {
// Add custom event for when source is finished downloading.
if (this.bufferedPercent() == 1) {
this.trigger('loadedalldata');
@@ -417,7 +442,7 @@ class Player extends Component {
* Fired when the end of the media resource is reached (currentTime == duration)
* @event ended
*/
- onEnded() {
+ handleEnded() {
this.addClass('vjs-ended');
if (this.options_['loop']) {
this.currentTime(0);
@@ -431,7 +456,7 @@ class Player extends Component {
* Fired when the duration of the media resource is first known or changed
* @event durationchange
*/
- onDurationChange() {
+ handleDurationChange() {
// Allows for caching value instead of asking player each time.
// We need to get the techGet response and check for a value so we don't
// accidentally cause the stack to blow up.
@@ -454,7 +479,7 @@ class Player extends Component {
* Fired when the player switches in or out of fullscreen mode
* @event fullscreenchange
*/
- onFullscreenChange() {
+ handleFullscreenChange() {
if (this.isFullscreen()) {
this.addClass('vjs-fullscreen');
} else {
@@ -500,11 +525,11 @@ class Player extends Component {
} catch(e) {
// When building additional tech libs, an expected method may not be defined yet
if (this.tech[method] === undefined) {
- Lib.log('Video.js: ' + method + ' method not defined for '+this.techName+' playback technology.', e);
+ Lib.log(`Video.js: ${method} method not defined for ${this.techName} playback technology.`, e);
} else {
// When a method isn't available on the object it throws a TypeError
if (e.name == 'TypeError') {
- Lib.log('Video.js: ' + method + ' unavailable on '+this.techName+' playback technology element.', e);
+ Lib.log(`Video.js: ${method} unavailable on ${this.techName} playback technology element.`, e);
this.tech.isReady_ = false;
} else {
Lib.log(e);
@@ -522,7 +547,7 @@ class Player extends Component {
*
* myPlayer.play();
*
- * @return {vjs.Player} self
+ * @return {Player} self
*/
play() {
this.techCall('play');
@@ -534,7 +559,7 @@ class Player extends Component {
*
* myPlayer.pause();
*
- * @return {vjs.Player} self
+ * @return {Player} self
*/
pause() {
this.techCall('pause');
@@ -554,6 +579,29 @@ class Player extends Component {
return (this.techGet('paused') === false) ? false : true;
}
+ /**
+ * Returns whether or not the user is "scrubbing". Scrubbing is when the user
+ * has clicked the progress bar handle and is dragging it along the progress bar.
+ * @param {Boolean} isScrubbing True/false the user is scrubbing
+ * @return {Boolean} The scrubbing status when getting
+ * @return {Object} The player when setting
+ */
+ scrubbing(isScrubbing) {
+ if (isScrubbing !== undefined) {
+ this.scrubbing_ = !!isScrubbing;
+
+ if (isScrubbing) {
+ this.addClass('vjs-scrubbing');
+ } else {
+ this.removeClass('vjs-scrubbing');
+ }
+
+ return this;
+ }
+
+ return this.scrubbing_;
+ }
+
/**
* Get or set the current time (in seconds)
*
@@ -565,7 +613,7 @@ class Player extends Component {
*
* @param {Number|String=} seconds The time to seek to
* @return {Number} The time in seconds, when not setting
- * @return {vjs.Player} self, when the current time is set
+ * @return {Player} self, when the current time is set
*/
currentTime(seconds) {
if (seconds !== undefined) {
@@ -605,7 +653,7 @@ class Player extends Component {
}
if (this.cache_.duration === undefined) {
- this.onDurationChange();
+ this.handleDurationChange();
}
return this.cache_.duration || 0;
@@ -723,7 +771,7 @@ class Player extends Component {
*
* @param {Number} percentAsDecimal The new volume as a decimal percent
* @return {Number} The current volume, when getting
- * @return {vjs.Player} self, when setting
+ * @return {Player} self, when setting
*/
volume(percentAsDecimal) {
let vol;
@@ -753,7 +801,7 @@ class Player extends Component {
*
* @param {Boolean=} muted True to mute, false to unmute
* @return {Boolean} True if mute is on, false if not, when getting
- * @return {vjs.Player} self, when setting mute
+ * @return {Player} self, when setting mute
*/
muted(muted) {
if (muted !== undefined) {
@@ -784,7 +832,7 @@ class Player extends Component {
*
* @param {Boolean=} isFS Update the player's fullscreen state
* @return {Boolean} true if fullscreen, false if not
- * @return {vjs.Player} self, when setting
+ * @return {Player} self, when setting
*/
isFullscreen(isFS) {
if (isFS !== undefined) {
@@ -815,7 +863,7 @@ class Player extends Component {
* This includes most mobile devices (iOS, Android) and older versions of
* Safari.
*
- * @return {vjs.Player} self
+ * @return {Player} self
*/
requestFullscreen() {
var fsApi = FullscreenApi;
@@ -872,7 +920,7 @@ class Player extends Component {
*
* myPlayer.exitFullscreen();
*
- * @return {vjs.Player} self
+ * @return {Player} self
*/
exitFullscreen() {
var fsApi = FullscreenApi;
@@ -952,7 +1000,7 @@ class Player extends Component {
// Check if the current tech is defined before continuing
if (!tech) {
- Lib.log.error('The "' + techName + '" tech is undefined. Skipped browser support check for that tech.');
+ Lib.log.error(`The "${techName}" tech is undefined. Skipped browser support check for that tech.`);
continue;
}
@@ -1005,13 +1053,9 @@ class Player extends Component {
* @return {String} The current video source when getting
* @return {String} The player when setting
*/
- src(source) {
+ src(source=this.techGet('src')) {
let currentTech = Component.getComponent(this.techName);
- if (source === undefined) {
- return this.techGet('src');
- }
-
// case: Array of source objects to choose from and pick the best to play
if (Lib.obj.isArray(source)) {
this.sourceList_(source);
@@ -1090,7 +1134,7 @@ class Player extends Component {
/**
* Begin loading the src data.
- * @return {vjs.Player} Returns the player
+ * @return {Player} Returns the player
*/
load() {
this.techCall('load');
@@ -1119,7 +1163,7 @@ class Player extends Component {
/**
* Get or set the preload attribute.
* @return {String} The preload attribute value when getting
- * @return {vjs.Player} Returns the player when setting
+ * @return {Player} Returns the player when setting
*/
preload(value) {
if (value !== undefined) {
@@ -1133,7 +1177,7 @@ class Player extends Component {
/**
* Get or set the autoplay attribute.
* @return {String} The autoplay attribute value when getting
- * @return {vjs.Player} Returns the player when setting
+ * @return {Player} Returns the player when setting
*/
autoplay(value) {
if (value !== undefined) {
@@ -1147,7 +1191,7 @@ class Player extends Component {
/**
* Get or set the loop attribute on the video element.
* @return {String} The loop attribute value when getting
- * @return {vjs.Player} Returns the player when setting
+ * @return {Player} Returns the player when setting
*/
loop(value) {
if (value !== undefined) {
@@ -1171,7 +1215,7 @@ class Player extends Component {
*
* @param {String=} [src] Poster image source URL
* @return {String} poster URL when getting
- * @return {vjs.Player} self when setting
+ * @return {Player} self when setting
*/
poster(src) {
if (src === undefined) {
@@ -1231,7 +1275,7 @@ class Player extends Component {
* if it can support native controls**
*
* @param {Boolean} bool True signals that native controls are on
- * @return {vjs.Player} Returns the player
+ * @return {Player} Returns the player
* @private
*/
usingNativeControls(bool) {
@@ -1247,7 +1291,7 @@ class Player extends Component {
* player is using the native device controls
*
* @event usingnativecontrols
- * @memberof vjs.Player
+ * @memberof Player
* @instance
* @private
*/
@@ -1259,7 +1303,7 @@ class Player extends Component {
* player is using the custom HTML controls
*
* @event usingcustomcontrols
- * @memberof vjs.Player
+ * @memberof Player
* @instance
* @private
*/
@@ -1274,8 +1318,8 @@ class Player extends Component {
/**
* Set or get the current MediaError
* @param {*} err A MediaError or a String/Number to be turned into a MediaError
- * @return {vjs.MediaError|null} when getting
- * @return {vjs.Player} when setting
+ * @return {MediaError|null} when getting
+ * @return {Player} when setting
*/
error(err) {
if (err === undefined) {
@@ -1304,7 +1348,7 @@ class Player extends Component {
// log the name of the error type and any message
// ie8 just logs "[object object]" if you just log the error object
- Lib.log.error('(CODE:'+this.error_.code+' '+MediaError.errorTypes[this.error_.code]+')', this.error_.message, this.error_);
+ Lib.log.error(`(CODE:${this.error_.code} ${MediaError.errorTypes[this.error_.code]})`, this.error_.message, this.error_);
return this;
}
@@ -1370,20 +1414,20 @@ class Player extends Component {
listenForUserActivity() {
let mouseInProgress, lastMoveX, lastMoveY;
- let onActivity = Lib.bind(this, this.reportUserActivity);
+ let handleActivity = Lib.bind(this, this.reportUserActivity);
- let onMouseMove = function(e) {
+ 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) {
lastMoveX = e.screenX;
lastMoveY = e.screenY;
- onActivity();
+ handleActivity();
}
};
- let onMouseDown = function() {
- onActivity();
+ let handleMouseDown = function() {
+ handleActivity();
// For as long as the they are touching the device or have their mouse down,
// we consider them active even if they're not moving their finger or mouse.
// So we want to continue to update that they are active
@@ -1391,24 +1435,24 @@ class Player extends Component {
// Setting userActivity=true now and setting the interval to the same time
// as the activityCheck interval (250) should ensure we never miss the
// next activityCheck
- mouseInProgress = this.setInterval(onActivity, 250);
+ mouseInProgress = this.setInterval(handleActivity, 250);
};
- let onMouseUp = function(event) {
- onActivity();
+ let handleMouseUp = function(event) {
+ handleActivity();
// Stop the interval that maintains activity if the mouse/touch is down
this.clearInterval(mouseInProgress);
};
// Any mouse movement will be considered user activity
- this.on('mousedown', onMouseDown);
- this.on('mousemove', onMouseMove);
- this.on('mouseup', onMouseUp);
+ this.on('mousedown', handleMouseDown);
+ this.on('mousemove', handleMouseMove);
+ this.on('mouseup', handleMouseUp);
// Listen for keyboard navigation
// Shouldn't need to use inProgress interval because of key repeat
- this.on('keydown', onActivity);
- this.on('keyup', onActivity);
+ this.on('keydown', handleActivity);
+ this.on('keyup', handleActivity);
// Run an interval every 250 milliseconds instead of stuffing everything into
// the mousemove/touchmove function itself, to prevent performance degradation.
@@ -1473,7 +1517,7 @@ class Player extends Component {
*
* @param {Boolean} bool True signals that this is an audio player.
* @return {Boolean} Returns true if player is audio, false if not when getting
- * @return {vjs.Player} Returns the player if setting
+ * @return {Player} Returns the player if setting
* @private
*/
isAudio(bool) {
@@ -1597,7 +1641,7 @@ class Player extends Component {
* The player's language code
* @param {String} languageCode The locale string
* @return {String} The locale string when getting
- * @return {vjs.Player} self, when setting
+ * @return {Player} self, when setting
*/
language(languageCode) {
if (languageCode === undefined) {
@@ -1628,7 +1672,7 @@ class Player extends Component {
if (dataSetup !== null){
// Parse options JSON
// If empty string, make it a parsable json object.
- Lib.obj.merge(tagOptions, JSON.parse(dataSetup || '{}'));
+ Lib.obj.merge(tagOptions, safeParseTuple(dataSetup || '{}')[1]);
}
Lib.obj.merge(baseOptions, tagOptions);
@@ -1661,9 +1705,9 @@ class Player extends Component {
Player.players = {};
/**
- * Player instance options, surfaced using vjs.options
- * vjs.options = vjs.Player.prototype.options_
- * Make changes in vjs.options, not here.
+ * Player instance options, surfaced using options
+ * options = Player.prototype.options_
+ * Make changes in options, not here.
* All options should use string keys so they avoid
* renaming by closure compiler
* @type {Object}
@@ -1675,31 +1719,31 @@ Player.prototype.options_ = Options;
* Fired when the player has initial duration and dimension information
* @event loadedmetadata
*/
-Player.prototype.onLoadedMetaData;
+Player.prototype.handleLoadedMetaData;
/**
* Fired when the player has downloaded data at the current playback position
* @event loadeddata
*/
-Player.prototype.onLoadedData;
+Player.prototype.handleLoadedData;
/**
* Fired when the player has finished downloading the source data
* @event loadedalldata
*/
-Player.prototype.onLoadedAllData;
+Player.prototype.handleLoadedAllData;
/**
* Fired when the user is active, e.g. moves the mouse over the player
* @event useractive
*/
-Player.prototype.onUserActive;
+Player.prototype.handleUserActive;
/**
* Fired when the user is inactive, e.g. a short delay after the last mouse move or control interaction
* @event userinactive
*/
-Player.prototype.onUserInactive;
+Player.prototype.handleUserInactive;
/**
* Fired when the current playback position has changed
@@ -1708,19 +1752,28 @@ Player.prototype.onUserInactive;
* playback technology in use.
* @event timeupdate
*/
-Player.prototype.onTimeUpdate;
+Player.prototype.handleTimeUpdate;
/**
* Fired when the volume changes
* @event volumechange
*/
-Player.prototype.onVolumeChange;
+Player.prototype.handleVolumeChange;
/**
* Fired when an error occurs
* @event error
*/
-Player.prototype.onError;
+Player.prototype.handleError;
+
+Player.prototype.flexNotSupported_ = function() {
+ var elem = document.createElement('i');
+
+ return !('flexBasis' in elem.style ||
+ 'webkitFlexBasis' in elem.style ||
+ 'mozFlexBasis' in elem.style ||
+ 'msFlexBasis' in elem.style);
+};
Component.registerComponent('Player', Player);
export default Player;
diff --git a/src/js/poster-image.js b/src/js/poster-image.js
index 0415e4565..0288770de 100644
--- a/src/js/poster-image.js
+++ b/src/js/poster-image.js
@@ -6,7 +6,7 @@ import * as Lib from './lib';
/**
* The component that handles showing the poster image.
*
- * @param {vjs.Player|Object} player
+ * @param {Player|Object} player
* @param {Object=} options
* @constructor
*/
@@ -79,7 +79,7 @@ class PosterImage extends Button {
// Any falsey values should stay as an empty string, otherwise
// this will throw an extra error
if (url) {
- backgroundImage = 'url("' + url + '")';
+ backgroundImage = `url("${url}")`;
}
this.el_.style.backgroundImage = backgroundImage;
@@ -89,10 +89,14 @@ class PosterImage extends Button {
/**
* Event handler for clicks on the poster image
*/
- onClick() {
+ handleClick() {
// We don't want a click to trigger playback when controls are disabled
// but CSS should be hiding the poster to prevent that from happening
- this.player_.play();
+ if (this.player_.paused()) {
+ this.player_.play();
+ } else {
+ this.player_.pause();
+ }
}
}
diff --git a/src/js/setup.js b/src/js/setup.js
index 107410230..b499a420c 100644
--- a/src/js/setup.js
+++ b/src/js/setup.js
@@ -1,4 +1,3 @@
-import JSON from './json';
import * as Events from './events';
import document from 'global/document';
import window from 'global/window';
diff --git a/src/js/slider/slider-handle.js b/src/js/slider/slider-handle.js
index edde4f5c9..07b33a68d 100644
--- a/src/js/slider/slider-handle.js
+++ b/src/js/slider/slider-handle.js
@@ -4,7 +4,7 @@ import * as Lib from '../lib.js';
/**
* SeekBar Behavior includes play progress bar, and seek handle
* Needed so it can determine seek position based on handle position/size
- * @param {vjs.Player|Object} player
+ * @param {Player|Object} player
* @param {Object=} options
* @constructor
*/
@@ -16,7 +16,7 @@ class SliderHandle extends Component {
// Add the slider element class to all sub classes
props.className = props.className + ' vjs-slider-handle';
props = Lib.obj.merge({
- innerHTML: ''+(this.defaultValue || 0)+' '
+ innerHTML: `${this.defaultValue || 0} `
}, props);
return super.createEl('div', props);
diff --git a/src/js/slider/slider.js b/src/js/slider/slider.js
index 39ddad4f3..856c43961 100644
--- a/src/js/slider/slider.js
+++ b/src/js/slider/slider.js
@@ -7,7 +7,7 @@ import document from 'global/document';
/**
* The base functionality for sliders like the volume bar and seek bar
*
- * @param {vjs.Player|Object} player
+ * @param {Player|Object} player
* @param {Object=} options
* @constructor
*/
@@ -23,18 +23,17 @@ class Slider extends Component {
// Set a horizontal or vertical class on the slider depending on the slider type
this.vertical(!!this.options()['vertical']);
- this.on('mousedown', this.onMouseDown);
- this.on('touchstart', this.onMouseDown);
- this.on('focus', this.onFocus);
- this.on('blur', this.onBlur);
- this.on('click', this.onClick);
+ this.on('mousedown', this.handleMouseDown);
+ this.on('touchstart', this.handleMouseDown);
+ this.on('focus', this.handleFocus);
+ this.on('blur', this.handleBlur);
+ this.on('click', this.handleClick);
this.on(player, 'controlsvisible', this.update);
this.on(player, this.playerEvent, this.update);
}
- createEl(type, props) {
- props = props || {};
+ createEl(type, props={}) {
// Add the slider element class to all sub classes
props.className = props.className + ' vjs-slider';
props = Lib.obj.merge({
@@ -48,30 +47,30 @@ class Slider extends Component {
return super.createEl(type, props);
}
- onMouseDown(event) {
+ handleMouseDown(event) {
event.preventDefault();
Lib.blockTextSelection();
this.addClass('vjs-sliding');
- this.on(document, 'mousemove', this.onMouseMove);
- this.on(document, 'mouseup', this.onMouseUp);
- this.on(document, 'touchmove', this.onMouseMove);
- this.on(document, 'touchend', this.onMouseUp);
+ this.on(document, 'mousemove', this.handleMouseMove);
+ this.on(document, 'mouseup', this.handleMouseUp);
+ this.on(document, 'touchmove', this.handleMouseMove);
+ this.on(document, 'touchend', this.handleMouseUp);
- this.onMouseMove(event);
+ this.handleMouseMove(event);
}
// To be overridden by a subclass
- onMouseMove() {}
+ handleMouseMove() {}
- onMouseUp() {
+ handleMouseUp() {
Lib.unblockTextSelection();
this.removeClass('vjs-sliding');
- this.off(document, 'mousemove', this.onMouseMove);
- this.off(document, 'mouseup', this.onMouseUp);
- this.off(document, 'touchmove', this.onMouseMove);
- this.off(document, 'touchend', this.onMouseUp);
+ this.off(document, 'mousemove', this.handleMouseMove);
+ this.off(document, 'mouseup', this.handleMouseUp);
+ this.off(document, 'touchmove', this.handleMouseMove);
+ this.off(document, 'touchend', this.handleMouseUp);
this.update();
}
@@ -207,11 +206,11 @@ class Slider extends Component {
}
}
- onFocus() {
- this.on(document, 'keydown', this.onKeyPress);
+ handleFocus() {
+ this.on(document, 'keydown', this.handleKeyPress);
}
- onKeyPress(event) {
+ handleKeyPress(event) {
if (event.which == 37 || event.which == 40) { // Left and Down Arrows
event.preventDefault();
this.stepBack();
@@ -221,8 +220,8 @@ class Slider extends Component {
}
}
- onBlur() {
- this.off(document, 'keydown', this.onKeyPress);
+ handleBlur() {
+ this.off(document, 'keydown', this.handleKeyPress);
}
/**
@@ -230,7 +229,7 @@ class Slider extends Component {
* from bubbling up to parent elements like button menus.
* @param {Object} event Event object
*/
- onClick(event) {
+ handleClick(event) {
event.stopImmediatePropagation();
event.preventDefault();
}
diff --git a/src/js/tech/flash-rtmp.js b/src/js/tech/flash-rtmp.js
index a821fff75..9f333cf9f 100644
--- a/src/js/tech/flash-rtmp.js
+++ b/src/js/tech/flash-rtmp.js
@@ -74,7 +74,7 @@ function FlashRtmpDecorator(Flash) {
* Adaptive source handlers will have more complicated workflows before passing
* video data to the video element
* @param {Object} source The source object
- * @param {vjs.Flash} tech The instance of the Flash tech
+ * @param {Flash} tech The instance of the Flash tech
*/
Flash.rtmpSourceHandler.handleSource = function(source, tech){
let srcParts = Flash.streamToParts(source.src);
diff --git a/src/js/tech/flash.js b/src/js/tech/flash.js
index 8821618bc..605c795bc 100644
--- a/src/js/tech/flash.js
+++ b/src/js/tech/flash.js
@@ -14,7 +14,7 @@ let navigator = window.navigator;
/**
* Flash Media Controller - Wrapper for fallback SWF API
*
- * @param {vjs.Player} player
+ * @param {Player} player
* @param {Object=} options
* @param {Function=} ready
* @constructor
@@ -221,7 +221,7 @@ Tech.withSourceHandlers(Flash);
* The default native source handler.
* This simply passes the source to the video element. Nothing fancy.
* @param {Object} source The source object
- * @param {vjs.Flash} tech The instance of the Flash tech
+ * @param {Flash} tech The instance of the Flash tech
*/
Flash.nativeSourceHandler = {};
@@ -236,7 +236,7 @@ Flash.nativeSourceHandler.canHandleSource = function(source){
function guessMimeType(src) {
var ext = Lib.getFileExtension(src);
if (ext) {
- return 'video/' + ext;
+ return `video/${ext}`;
}
return '';
}
@@ -260,7 +260,7 @@ Flash.nativeSourceHandler.canHandleSource = function(source){
* Adaptive source handlers will have more complicated workflows before passing
* video data to the video element
* @param {Object} source The source object
- * @param {vjs.Flash} tech The instance of the Flash tech
+ * @param {Flash} tech The instance of the Flash tech
*/
Flash.nativeSourceHandler.handleSource = function(source, tech){
tech.setSrc(source.src);
@@ -379,7 +379,7 @@ Flash.getEmbedCode = function(swf, flashVars, params, attributes){
// Convert flash vars to string
if (flashVars) {
Lib.obj.each(flashVars, function(key, val){
- flashVarsString += (key + '=' + val + '&');
+ flashVarsString += `${key}=${val}&`;
});
}
@@ -393,7 +393,7 @@ Flash.getEmbedCode = function(swf, flashVars, params, attributes){
// Create param tags string
Lib.obj.each(params, function(key, val){
- paramsString += ' ';
+ paramsString += ` `;
});
attributes = Lib.obj.merge({
@@ -408,10 +408,10 @@ Flash.getEmbedCode = function(swf, flashVars, params, attributes){
// Create Attributes string
Lib.obj.each(attributes, function(key, val){
- attrsString += (key + '="' + val + '" ');
+ attrsString += `${key}="${val}" `;
});
- return objTag + attrsString + '>' + paramsString + ' ';
+ return `${objTag}${attrsString}>${paramsString} `;
};
// Run Flash through the RTMP decorator
diff --git a/src/js/tech/html5.js b/src/js/tech/html5.js
index 8d32bd37b..739be2dbe 100644
--- a/src/js/tech/html5.js
+++ b/src/js/tech/html5.js
@@ -10,7 +10,7 @@ import document from 'global/document';
/**
* HTML5 Media Controller - Wrapper for HTML5 Media API
- * @param {vjs.Player|Object} player
+ * @param {Player|Object} player
* @param {Object=} options
* @param {Function=} ready
* @constructor
@@ -362,13 +362,12 @@ class Html5 extends Tech {
return this.el_.addTextTrack(kind, label, language);
}
- addRemoteTextTrack(options) {
+ addRemoteTextTrack(options={}) {
if (!this['featuresNativeTextTracks']) {
return super.addRemoteTextTrack(options);
}
var track = document.createElement('track');
- options = options || {};
if (options['kind']) {
track['kind'] = options['kind'];
@@ -460,7 +459,7 @@ Tech.withSourceHandlers(Html5);
* The default native source handler.
* This simply passes the source to the video element. Nothing fancy.
* @param {Object} source The source object
- * @param {vjs.Html5} tech The instance of the HTML5 tech
+ * @param {Html5} tech The instance of the HTML5 tech
*/
Html5.nativeSourceHandler = {};
@@ -489,7 +488,7 @@ Html5.nativeSourceHandler.canHandleSource = function(source){
// If no type, fall back to checking 'video/[EXTENSION]'
ext = Lib.getFileExtension(source.src);
- return canPlayType('video/'+ext);
+ return canPlayType(`video/${ext}`);
}
return '';
@@ -500,7 +499,7 @@ Html5.nativeSourceHandler.canHandleSource = function(source){
* Adaptive source handlers will have more complicated workflows before passing
* video data to the video element
* @param {Object} source The source object
- * @param {vjs.Html5} tech The instance of the Html5 tech
+ * @param {Html5} tech The instance of the Html5 tech
*/
Html5.nativeSourceHandler.handleSource = function(source, tech){
tech.setSrc(source.src);
diff --git a/src/js/tech/tech.js b/src/js/tech/tech.js
index edc7cd877..0aab1caaa 100644
--- a/src/js/tech/tech.js
+++ b/src/js/tech/tech.js
@@ -12,14 +12,13 @@ import document from 'global/document';
/**
* Base class for media (HTML5 Video, Flash) controllers
- * @param {vjs.Player|Object} player Central player instance
+ * @param {Player|Object} player Central player instance
* @param {Object=} options Options object
* @constructor
*/
class Tech extends Component {
- constructor(player, options, ready){
- options = options || {};
+ constructor(player, options={}, ready=function(){}){
// we don't want the tech to report user activity automatically.
// This is done manually in addControlsListeners
options.reportTouchActivity = false;
@@ -102,7 +101,7 @@ class Tech extends Component {
// trigger mousedown/up.
// http://stackoverflow.com/questions/1444562/javascript-onclick-event-over-flash-object
// Any touch events are set to block the mousedown event from happening
- this.on('mousedown', this.onClick);
+ this.on('mousedown', this.handleClick);
// If the controls were hidden we don't want that to change without a tap event
// so we'll check if the controls were already showing before reporting user
@@ -127,7 +126,7 @@ class Tech extends Component {
// The tap listener needs to come after the touchend listener because the tap
// listener cancels out any reportedUserActivity when setting userActive(false)
- this.on('tap', this.onTap);
+ this.on('tap', this.handleTap);
}
/**
@@ -150,7 +149,7 @@ class Tech extends Component {
/**
* Handle a click on the media element. By default will play/pause the media.
*/
- onClick(event) {
+ handleClick(event) {
// We're using mousedown to detect clicks thanks to Flash, but mousedown
// will also be triggered with right-clicks, so we need to prevent that
if (event.button !== 0) return;
@@ -170,7 +169,7 @@ class Tech extends Component {
* Handle a tap on the media element. By default it will toggle the user
* activity state, which hides and shows the controls.
*/
- onTap() {
+ handleTap() {
this.player().userActive(!this.player().userActive());
}
@@ -386,11 +385,9 @@ class Tech extends Component {
*/
Tech.prototype.textTracks_;
-var createTrackHelper = function(self, kind, label, language, options) {
+var createTrackHelper = function(self, kind, label, language, options={}) {
let tracks = self.textTracks();
- options = options || {};
-
options['kind'] = kind;
if (label) {
options['label'] = label;
diff --git a/src/js/tracks/text-track-display.js b/src/js/tracks/text-track-display.js
index f2dcbddbb..7ca83acab 100644
--- a/src/js/tracks/text-track-display.js
+++ b/src/js/tracks/text-track-display.js
@@ -136,13 +136,13 @@ class TextTrackDisplay extends Component {
}
if (overrides.edgeStyle) {
if (overrides.edgeStyle === 'dropshadow') {
- cueDiv.firstChild.style.textShadow = '2px 2px 3px ' + darkGray + ', 2px 2px 4px ' + darkGray + ', 2px 2px 5px ' + darkGray;
+ cueDiv.firstChild.style.textShadow = `2px 2px 3px ${darkGray}, 2px 2px 4px ${darkGray}, 2px 2px 5px ${darkGray}`;
} else if (overrides.edgeStyle === 'raised') {
- cueDiv.firstChild.style.textShadow = '1px 1px ' + darkGray + ', 2px 2px ' + darkGray + ', 3px 3px ' + darkGray;
+ cueDiv.firstChild.style.textShadow = `1px 1px ${darkGray}, 2px 2px ${darkGray}, 3px 3px ${darkGray}`;
} else if (overrides.edgeStyle === 'depressed') {
- cueDiv.firstChild.style.textShadow = '1px 1px ' + lightGray + ', 0 1px ' + lightGray + ', -1px -1px ' + darkGray + ', 0 -1px ' + darkGray;
+ cueDiv.firstChild.style.textShadow = `1px 1px ${lightGray}, 0 1px ${lightGray}, -1px -1px ${darkGray}, 0 -1px ${darkGray}`;
} else if (overrides.edgeStyle === 'uniform') {
- cueDiv.firstChild.style.textShadow = '0 0 4px ' + darkGray + ', 0 0 4px ' + darkGray + ', 0 0 4px ' + darkGray + ', 0 0 4px ' + darkGray;
+ cueDiv.firstChild.style.textShadow = `0 0 4px ${darkGray}, 0 0 4px ${darkGray}, 0 0 4px ${darkGray}, 0 0 4px ${darkGray}`;
}
}
if (overrides.fontPercent && overrides.fontPercent !== 1) {
diff --git a/src/js/tracks/text-track-settings.js b/src/js/tracks/text-track-settings.js
index fed7111bb..e2cbe26ff 100644
--- a/src/js/tracks/text-track-settings.js
+++ b/src/js/tracks/text-track-settings.js
@@ -1,6 +1,7 @@
import Component from '../component';
import * as Lib from '../lib';
import * as Events from '../events';
+import safeParseTuple from 'safe-json-parse/tuple';
import window from 'global/window';
class TextTrackSettings extends Component {
@@ -105,7 +106,7 @@ class TextTrackSettings extends Component {
restoreSettings() {
let values;
try {
- values = JSON.parse(window.localStorage.getItem('vjs-text-track-settings'));
+ values = safeParseTuple(window.localStorage.getItem('vjs-text-track-settings'))[1];
} catch (e) {}
if (values) {
@@ -168,118 +169,120 @@ function setSelectedOption(target, value) {
}
function captionOptionsMenuTemplate() {
- return '' +
- '
' +
- '
' +
- 'Foreground ' +
- '' +
- '--- ' +
- 'White ' +
- 'Black ' +
- 'Red ' +
- 'Green ' +
- 'Blue ' +
- 'Yellow ' +
- 'Magenta ' +
- 'Cyan ' +
- ' ' +
- '' +
- '' +
- '--- ' +
- 'Opaque ' +
- 'Semi-Opaque ' +
- ' ' +
- ' ' +
- '
' + // vjs-fg-color
- '
' +
- 'Background ' +
- '' +
- '--- ' +
- 'White ' +
- 'Black ' +
- 'Red ' +
- 'Green ' +
- 'Blue ' +
- 'Yellow ' +
- 'Magenta ' +
- 'Cyan ' +
- ' ' +
- '' +
- '' +
- '--- ' +
- 'Opaque ' +
- 'Semi-Transparent ' +
- 'Transparent ' +
- ' ' +
- ' ' +
- '
' + // vjs-bg-color
- '
' +
- 'Window ' +
- '' +
- '--- ' +
- 'White ' +
- 'Black ' +
- 'Red ' +
- 'Green ' +
- 'Blue ' +
- 'Yellow ' +
- 'Magenta ' +
- 'Cyan ' +
- ' ' +
- '' +
- '' +
- '--- ' +
- 'Opaque ' +
- 'Semi-Transparent ' +
- 'Transparent ' +
- ' ' +
- ' ' +
- '
' + // vjs-window-color
- '
' + // vjs-tracksettings
- '
' +
- '
' +
- 'Font Size ' +
- '' +
- '50% ' +
- '75% ' +
- '100% ' +
- '125% ' +
- '150% ' +
- '175% ' +
- '200% ' +
- '300% ' +
- '400% ' +
- ' ' +
- '
' + // vjs-font-percent
- '
' +
- 'Text Edge Style ' +
- '' +
- 'None ' +
- 'Raised ' +
- 'Depressed ' +
- 'Uniform ' +
- 'Dropshadow ' +
- ' ' +
- '
' + // vjs-edge-style
- '
' +
- 'Font Family ' +
- '' +
- 'Default ' +
- 'Monospace Serif ' +
- 'Proportional Serif ' +
- 'Monospace Sans-Serif ' +
- 'Proportional Sans-Serif ' +
- 'Casual ' +
- 'Script ' +
- 'Small Caps ' +
- ' ' +
- '
' + // vjs-font-family
- '
' +
- '
' +
- '' +
- 'Defaults ' +
- 'Done ' +
- '
';
+ let template = `
+
+
+ Foreground
+
+ ---
+ White
+ Black
+ Red
+ Green
+ Blue
+ Yellow
+ Magenta
+ Cyan
+
+
+
+ ---
+ Opaque
+ Semi-Opaque
+
+
+
+
+ Background
+
+ ---
+ White
+ Black
+ Red
+ Green
+ Blue
+ Yellow
+ Magenta
+ Cyan
+
+
+
+ ---
+ Opaque
+ Semi-Transparent
+ Transparent
+
+
+
+
+ Window
+
+ ---
+ White
+ Black
+ Red
+ Green
+ Blue
+ Yellow
+ Magenta
+ Cyan
+
+
+
+ ---
+ Opaque
+ Semi-Transparent
+ Transparent
+
+
+
+
+
+
+ Font Size
+
+ 50%
+ 75%
+ 100%
+ 125%
+ 150%
+ 175%
+ 200%
+ 300%
+ 400%
+
+
+
+ Text Edge Style
+
+ None
+ Raised
+ Depressed
+ Uniform
+ Dropshadow
+
+
+
+ Font Family
+
+ Default
+ Monospace Serif
+ Proportional Serif
+ Monospace Sans-Serif
+ Proportional Sans-Serif
+ Casual
+ Script
+ Small Caps
+
+
+
+
+
+ Defaults
+ Done
+
`;
+
+ return template;
}
export default TextTrackSettings;
diff --git a/src/js/tracks/text-track.js b/src/js/tracks/text-track.js
index 25c974100..f89d250a4 100644
--- a/src/js/tracks/text-track.js
+++ b/src/js/tracks/text-track.js
@@ -28,9 +28,7 @@ import XHR from '../xhr.js';
* attribute EventHandler oncuechange;
* };
*/
-let TextTrack = function(options) {
- options = options || {};
-
+let TextTrack = function(options={}) {
if (!options['player']) {
throw new Error('A player was not provided.');
}
diff --git a/src/js/video.js b/src/js/video.js
index bdbec3504..7b709efdd 100644
--- a/src/js/video.js
+++ b/src/js/video.js
@@ -15,7 +15,8 @@ import * as setup from './setup';
import Component from './component';
import * as Lib from './lib';
import * as Util from './util.js';
-
+import Player from './player';
+import extendsFn from './extends.js';
if (typeof HTMLVideoElement === 'undefined') {
document.createElement('video');
@@ -36,9 +37,10 @@ videojs.TOUCH_ENABLED = Lib.TOUCH_ENABLED;
videojs.util = Util;
// Probably want to keep this one for 5.0?
-import Player from './player';
videojs.players = Player.players;
+videojs.extends = extendsFn;
+
// REMOVING: We probably should not include this in 5.0 thought it would make it
// more backwards compatible
// // Expose but deprecate the window[componentName] method for accessing components
@@ -55,6 +57,4 @@ videojs.players = Player.players;
// Lib.obj.merge(module.exports[name], component);
// });
-
-
export default videojs;
diff --git a/test/api/api.js b/test/api/api.js
index 483f6ad96..c627f77dd 100644
--- a/test/api/api.js
+++ b/test/api/api.js
@@ -255,4 +255,27 @@ function testHelperMakeTag(){
return videoTag;
}
-})();
\ No newline at end of file
+test('should extend Component', function(){
+ var Component = videojs.getComponent('Component');
+ var MyComponent = videojs.extends(Component, {
+ constructor: function() {
+ this.bar = true;
+ },
+ foo: function() {
+ return true;
+ }
+ });
+
+ var myComponent = new MyComponent();
+ ok(myComponent instanceof Component, 'creates an instance of Component');
+ ok(myComponent instanceof MyComponent, 'creates an instance of MyComponent');
+ ok(myComponent.bar, 'the constructor function is used');
+ ok(myComponent.foo(), 'instance methods are applied');
+
+ var NoMethods = videojs.extends(Component);
+ var noMethods = new NoMethods({});
+ ok(noMethods.on, 'should extend component with no methods or constructor');
+});
+
+
+})();
diff --git a/test/globals-shim.js b/test/globals-shim.js
new file mode 100644
index 000000000..cbcf7b034
--- /dev/null
+++ b/test/globals-shim.js
@@ -0,0 +1,10 @@
+import window from 'global/window';
+import sinon from 'sinon';
+
+window.q = QUnit;
+window.sinon = sinon;
+
+// This may not be needed anymore, but double check before removing
+window.fixture = document.createElement('div');
+fixture.id = 'qunit-fixture';
+document.body.appendChild(fixture);
diff --git a/test/index.html b/test/index.html
new file mode 100644
index 000000000..41b1268b6
--- /dev/null
+++ b/test/index.html
@@ -0,0 +1,15 @@
+
+
+
+
+ VideoJS Tests
+
+
+
+
+
+
+
+
+
+
diff --git a/test/karma-qunit-shim.js b/test/karma-qunit-shim.js
deleted file mode 100644
index 18611a8d2..000000000
--- a/test/karma-qunit-shim.js
+++ /dev/null
@@ -1,6 +0,0 @@
-var q = QUnit;
-
-// This may not be needed anymore, but double check before removing
-var fixture = document.createElement('div');
-fixture.id = 'qunit-fixture';
-document.body.appendChild(fixture);
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
index 40b9773a6..9c5876f03 100644
--- a/test/karma.conf.js
+++ b/test/karma.conf.js
@@ -50,20 +50,16 @@ module.exports = function(config) {
config.set({
basePath: '',
- frameworks: ['browserify', 'qunit', 'sinon'],
+ frameworks: ['browserify', 'qunit'],
autoWatch: false,
singleRun: true,
- // customLaunchers: customLaunchers,
-
files: [
'../build/temp/video-js.min.css',
- '../test/karma-qunit-shim.js',
- '../test/unit/**/*.js',
'../build/temp/video.min.js',
- '../test/api/**/*.js',
+ '../build/temp/tests.js',
],
preprocessors: {
@@ -84,7 +80,6 @@ module.exports = function(config) {
'karma-phantomjs-launcher',
'karma-safari-launcher',
'karma-sauce-launcher',
- 'karma-sinon',
'karma-browserify',
'karma-coverage'
],
diff --git a/test/unit/component.js b/test/unit/component.js
index 82b001621..e5b53f481 100644
--- a/test/unit/component.js
+++ b/test/unit/component.js
@@ -41,7 +41,7 @@ test('should add a child component', function(){
test('should init child components from options', function(){
var comp = new Component(getFakePlayer(), {
children: {
- 'component': true
+ 'component': {}
}
});
diff --git a/test/unit/mediafaker.js b/test/unit/mediafaker.js
index f0b0b4501..fbb93a7f6 100644
--- a/test/unit/mediafaker.js
+++ b/test/unit/mediafaker.js
@@ -10,8 +10,8 @@ import Component from '../../src/js/component.js';
*/
class MediaFaker extends Tech {
- constructor(player, options, onReady){
- super(player, options, onReady);
+ constructor(player, options, handleReady){
+ super(player, options, handleReady);
this.triggerReady();
}
diff --git a/test/unit/player.js b/test/unit/player.js
index f18105760..aa63119f0 100644
--- a/test/unit/player.js
+++ b/test/unit/player.js
@@ -441,7 +441,7 @@ test('should not add multiple first play events despite subsequent loads', funct
ok(true, 'First play should fire once.');
});
- // Checking to make sure onLoadStart removes first play listener before adding a new one.
+ // Checking to make sure handleLoadStart removes first play listener before adding a new one.
player.trigger('loadstart');
player.trigger('loadstart');
player.trigger('play');
@@ -702,3 +702,29 @@ test('should add an audio class if an audio el is used', function() {
ok(player.el().className.indexOf(audioClass) !== -1, 'added '+ audioClass +' css class');
});
+
+test('should not be scrubbing while not seeking', function(){
+ var player = TestHelpers.makePlayer();
+ equal(player.scrubbing(), false, 'player is not scrubbing');
+ ok(player.el().className.indexOf('scrubbing') === -1, 'scrubbing class is not present');
+ player.scrubbing(false);
+ equal(player.scrubbing(), false, 'player is not scrubbing');
+});
+
+test('should be scrubbing while seeking', function(){
+ var player = TestHelpers.makePlayer();
+ player.scrubbing(true);
+ equal(player.scrubbing(), true, 'player is scrubbing');
+ ok(player.el().className.indexOf('scrubbing') !== -1, 'scrubbing class is present');
+});
+
+test('should throw on startup no techs are specified', function() {
+ const techOrder = Options.techOrder;
+
+ Options.techOrder = null;
+ q.throws(function() {
+ videojs(TestHelpers.makeTag());
+ }, 'a falsey techOrder should throw');
+
+ Options.techOrder = techOrder;
+});
diff --git a/test/unit/tracks/text-track-settings.js b/test/unit/tracks/text-track-settings.js
index d7bfcdb2a..2e5d439f8 100644
--- a/test/unit/tracks/text-track-settings.js
+++ b/test/unit/tracks/text-track-settings.js
@@ -1,6 +1,7 @@
import TextTrackSettings from '../../../src/js/tracks/text-track-settings.js';
import TestHelpers from '../test-helpers.js';
import * as Events from '../../../src/js/events.js';
+import safeParseTuple from 'safe-json-parse/tuple';
import window from 'global/window';
var tracks = [{
@@ -45,7 +46,7 @@ test('should update settings', function() {
equal(player.el().querySelector('.vjs-font-percent select').selectedIndex, 3, 'font-percent is set to new value');
Events.trigger(player.el().querySelector('.vjs-done-button'), 'click');
- deepEqual(JSON.parse(window.localStorage.getItem('vjs-text-track-settings')), newSettings, 'values are saved');
+ deepEqual(safeParseTuple(window.localStorage.getItem('vjs-text-track-settings'))[1], newSettings, 'values are saved');
});
test('should restore default settings', function() {