Comparar commits

..

20 Commits

Autor SHA1 Mensagem Data
Gary Katsevman 8607f882be v5.4.2 dist 2015-12-08 19:00:29 -05:00
Gary Katsevman 565dba8671 v5.4.2 2015-12-08 18:59:59 -05:00
Gary Katsevman a528e44d9b @gkatsev updated grunt-release config. closes #2900 2015-12-08 18:59:02 -05:00
Gary Katsevman 996822ba68 v5.4.1 2015-12-08 15:53:02 -05:00
Gary Katsevman 359df7148b @gkatsev added chg- and github- release for next releases. closes #2899 2015-12-08 15:52:17 -05:00
Gary Katsevman c6bf2b847a v5.4.0 2015-12-08 13:56:28 -05:00
Gary Katsevman 44edb12700 @gkatsev added ability to release next tag from master. closes #2894 2015-12-08 13:03:14 -05:00
Gary Katsevman 5bb1a76c4e @gkatsev added nullcheck for cues in updateForTrack. Fixes #2870. closes #2896 2015-12-08 11:43:14 -05:00
Carey Hinoki 8f2bc92412 @chemoish emulated HTMLTrackElement to enable track load events. closes #2804 2015-12-08 11:24:51 -05:00
Gary Katsevman e78e26b8a4 @gkatsev added a Player#reset method. Fixes #2852. closes #2880 2015-12-07 17:45:50 -05:00
Nicholas Fantozz 9e3a7b6159 @nick11703 changed multiline comments in sass with single-line comments. closes #2827 2015-12-07 16:30:26 -05:00
Gary Katsevman 0b7a2e41b3 @gkatsev added Player#tech. Fixes #2617. closes #2883 2015-12-07 16:27:33 -05:00
Pat O'Neill f225d4e68a @misteroneill updated videojs-ie8 to 1.1.1. closes #2869 2015-12-07 16:24:18 -05:00
Gary Katsevman a601fbb83f v5.3.0 2015-11-25 17:14:05 -05:00
jrivera 69b89e51f4 @imbcmdth added sourceOrder option for source-first ordering in selectSource. closes #2847 2015-11-25 17:11:36 -05:00
jforbes 8acd28c15a @forbesjo updated formatTime to not go negative. closes #2821 2015-11-25 16:46:41 -05:00
Matthew b188781fa9 v5.2.4 2015-11-25 21:31:49 +00:00
Matthew McClure 5ed0dc8adb @mmcc fixed vertical volume. closes #2859 2015-11-25 16:18:34 -05:00
Garrett Singer 72f77d77c9 @gesinger fixed handler explosion for cuechange events. closes #2849 2015-11-25 16:13:23 -05:00
Garrett Singer 7171ea8d42 @gesinger checked for track changes before tech started listening. closes #2835 2015-11-25 16:00:49 -05:00
51 arquivos alterados com 3063 adições e 971 exclusões
+22
Ver Arquivo
@@ -6,6 +6,28 @@ _(none)_
--------------------
## 5.4.2 (2015-12-08)
* @gkatsev updated grunt-release config ([view](https://github.com/videojs/video.js/pull/2900))
## 5.4.1 (2015-12-08)
* @misteroneill updated videojs-ie8 to 1.1.1 ([view](https://github.com/videojs/video.js/pull/2869))
* @gkatsev added Player#tech. Fixes #2617 ([view](https://github.com/videojs/video.js/pull/2883))
* @nick11703 changed multiline comments in sass with single-line comments ([view](https://github.com/videojs/video.js/pull/2827))
* @gkatsev added a Player#reset method. Fixes #2852 ([view](https://github.com/videojs/video.js/pull/2880))
* @chemoish emulated HTMLTrackElement to enable track load events ([view](https://github.com/videojs/video.js/pull/2804))
* @gkatsev added nullcheck for cues in updateForTrack. Fixes #2870 ([view](https://github.com/videojs/video.js/pull/2896))
* @gkatsev added ability to release next tag from master ([view](https://github.com/videojs/video.js/pull/2894))
* @gkatsev added chg- and github- release for next releases ([view](https://github.com/videojs/video.js/pull/2899))
## 5.3.0 (2015-11-25)
* @forbesjo updated formatTime to not go negative ([view](https://github.com/videojs/video.js/pull/2821))
* @imbcmdth added sourceOrder option for source-first ordering in selectSource ([view](https://github.com/videojs/video.js/pull/2847))
## 5.2.4 (2015-11-25)
* @gesinger checked for track changes before tech started listening ([view](https://github.com/videojs/video.js/pull/2835))
* @gesinger fixed handler explosion for cuechange events ([view](https://github.com/videojs/video.js/pull/2849))
* @mmcc fixed vertical volume ([view](https://github.com/videojs/video.js/pull/2859))
## 5.2.3 (2015-11-24)
* @gkatsev fixed clearing out errors ([view](https://github.com/videojs/video.js/pull/2850))
+19 -5
Ver Arquivo
@@ -294,11 +294,25 @@ module.exports = function(grunt) {
auth: {
user: process.env.VJS_GITHUB_USER,
password: process.env.VJS_GITHUB_TOKEN
},
release: {
tag_name: 'v'+ version.full,
name: version.full,
body: require('chg').find(version.full).changesRaw
}
},
release: {
options: {
release: {
tag_name: 'v'+ version.full,
name: version.full,
body: require('chg').find(version.full).changesRaw
}
}
},
prerelease: {
options: {
release: {
tag_name: 'v'+ version.full,
name: version.full,
body: require('chg').find(version.full).changesRaw,
prerelease: true
}
}
},
files: {
+1 -1
Ver Arquivo
@@ -1,7 +1,7 @@
{
"name": "video.js",
"description": "An HTML5 and Flash video player with a common API and skin for both.",
"version": "5.2.3",
"version": "5.4.2",
"keywords": [
"videojs",
"html5",
+27 -3
Ver Arquivo
@@ -250,15 +250,37 @@
]
},
"next": {
"patch": {
"description": "Create a patch release and tag it @next on npm",
"release_type": "patch",
"steps": [{ "include": "release run_next" }]
},
"minor": {
"description": "Create a minor release and tag it @next on npm",
"release_type": "minor",
"steps": [{ "include": "release run_next" }]
},
"major": {
"description": "Create a major release and tag it @next on npm",
"release_type": "major",
"steps": [{ "include": "release run_next" }]
}
},
"prerelease": {
"release_type": "prerelease",
"steps": [{ "include": "release run_next" }]
},
"run_next": {
"steps": [
[ "git checkout master", "Checkout the developmet branch" ],
[ "git pull upstream master", "Update the developmet branch" ],
{ "include": "branch check" },
{ "include": "update local master" },
[ "git checkout -b temp-release-branch master","Create a temporary branch for the dist" ],
[ "grunt version:{{release_type}}", "Bump package versions" ],
[ "./build/bin/version", "Return the current VJS Version from the package.json file", "version" ],
[ "grunt chg-release:{{version}}", "Update the changelog with the new release" ],
[ "git commit -am 'v{{version}}'", "Add and commit the package changes" ],
[ "git checkout master", "Checkout the developmet branch" ],
[ "git merge temp-release-branch", "Merge package changes into the dev brach" ],
@@ -269,11 +291,13 @@
[ "git commit -m 'v{{version}} dist'", "Commit the dist changes" ],
[ "git tag -a v{{version}} -m 'v{{version}}'", "Tag the release" ],
[ "git push upstream --tags", "Push the new tag to the repo" ],
[ "grunt github-release:prerelease", "Create a new pre-release on Github" ],
[ "npm publish --tag next", "Publish to npm as 'next'" ],
[ "git checkout master", "Checkout the developmet branch" ],
[ "git branch -D temp-release-branch", "Delete the temp release branch" ]
]
},
"run": {
"steps": [
{ "include": "branch check" },
@@ -292,7 +316,7 @@
[ "git tag -a v{{version}} -m 'v{{version}}'", "Tag the release" ],
[ "git push upstream --tags", "Push the new tag to the repo" ],
[ "npm publish", "Publish to npm" ],
[ "grunt github-release", "Create a new release on Github" ],
[ "grunt github-release:release", "Create a new release on Github" ],
[ "git checkout stable", "Checkout the developmet branch" ],
[ "git branch -D temp-release-branch", "Delete the temp release branch" ]
]
+637 -154
Ver Arquivo
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+9 -8
Ver Arquivo
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
+652 -321
Ver Arquivo
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+1 -1
Ver Arquivo
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
Arquivo binário não exibido.
+8 -102
Ver Arquivo
@@ -231,60 +231,43 @@
content: ""; }
.video-js {
/* display:inline-block would be closer to the video el's display:inline
* but it results in flash reloading when going into fullscreen [#2205]
*/
display: block;
/* Make video.js videos align top when next to video elements */
vertical-align: top;
box-sizing: border-box;
color: #fff;
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: 10px;
line-height: 1;
/* Provide some basic defaults for fonts */
font-weight: normal;
font-style: normal;
/* Avoiding helvetica: issue #376 */
font-family: Arial, Helvetica, sans-serif;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
/* Fix for Firefox 9 fullscreen (only if it is enabled). Not needed when
checking fullScreenEnabled. */ }
user-select: none; }
.video-js:-moz-full-screen {
position: absolute; }
.video-js:-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; }
/* List style reset */
.video-js ul {
font-family: inherit;
font-size: inherit;
line-height: inherit;
list-style-position: outside;
/* Important to specify each */
margin-left: 0;
margin-right: 0;
margin-top: 0;
margin-bottom: 0; }
/* Fill the width of the containing element and use padding to create the
desired aspect ratio. Default to 16x9 unless another ratio is given. */
/* Not including a default AR in vjs-fluid because it would override
the user set AR injected into the header. */
.video-js.vjs-fluid,
.video-js.vjs-16-9,
.video-js.vjs-4-3 {
@@ -302,8 +285,6 @@
width: 100%;
height: 100%; }
/* Playback technology elements expand to the width/height of the containing div
<video> or <object> */
.video-js .vjs-tech {
position: absolute;
top: 0;
@@ -311,12 +292,10 @@
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; }
.vjs-full-window .video-js.vjs-fullscreen {
@@ -331,13 +310,11 @@ body.vjs-full-window {
.video-js.vjs-fullscreen {
width: 100% !important;
height: 100% !important;
/* Undo any aspect ratio padding for fluid layouts */
padding-top: 0 !important; }
.video-js.vjs-fullscreen.vjs-user-inactive {
cursor: none; }
/* Hide disabled or unsupported controls. */
.vjs-hidden {
display: none !important; }
@@ -353,10 +330,6 @@ body.vjs-full-window {
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: #fff;
@@ -385,7 +358,6 @@ about what's required to play video. */
cursor: pointer;
opacity: 1;
border: 0.06666em solid #fff;
/* Need a slightly gray bg so it can be seen on black backgrounds */
background-color: #2B333F;
background-color: rgba(43, 51, 63, 0.7);
-webkit-border-radius: 0.3em;
@@ -451,7 +423,6 @@ about what's required to play video. */
margin: 0;
overflow: auto; }
/* prevent menus from opening while scrubbing (FF, IE) */
.vjs-scrubbing .vjs-menu-button:hover .vjs-menu {
display: none; }
@@ -492,20 +463,16 @@ about what's required to play video. */
bottom: 0;
width: 10em;
left: -3em;
/* (Width of vjs-menu - width of button) / 2 */
height: 0em;
margin-bottom: 1.5em;
border-top-color: rgba(43, 51, 63, 0.7);
/* Same as ul background */ }
border-top-color: rgba(43, 51, 63, 0.7); }
/* Button Pop-up Menu */
.vjs-menu-button-popup .vjs-menu ul {
.vjs-menu-button-popup .vjs-menu .vjs-menu-content {
background-color: #2B333F;
background-color: rgba(43, 51, 63, 0.7);
position: absolute;
width: 100%;
bottom: 1.5em;
/* Same bottom as vjs-menu border-top */
max-height: 15em; }
.vjs-menu-button-popup:hover .vjs-menu,
@@ -605,23 +572,16 @@ about what's required to play video. */
.vjs-controls-disabled .vjs-control-bar,
.vjs-using-native-controls .vjs-control-bar,
.vjs-error .vjs-control-bar {
/* !important is ok in this context. */
display: none !important; }
.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
*/
@media screen {
.vjs-user-inactive.vjs-playing .vjs-control-bar :before {
content: ""; } }
/* IE 8 + 9 Support */
.vjs-has-started.vjs-no-flex .vjs-control-bar {
display: table; }
@@ -642,13 +602,11 @@ fonts to show/hide properly.
font-size: 1.8em;
line-height: 1.67; }
/* 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 white; }
/* Hide control text visually, but have it available for screenreaders */
.video-js .vjs-control-text {
border: 0;
clip: rect(0 0 0 0);
@@ -659,7 +617,6 @@ fonts to show/hide properly.
position: absolute;
width: 1px; }
/* IE 8 + 9 Support */
.vjs-no-flex .vjs-control {
display: table-cell;
vertical-align: middle; }
@@ -667,19 +624,6 @@ fonts to show/hide properly.
.video-js .vjs-custom-control-spacer {
display: none; }
/**
* Let's talk pixel math!
* Start with a base font size of 10px (assuming that hasn't changed)
* No Hover:
* - Progress holder is 3px
* - Progress handle is 9px
* - Progress handle is pulled up 3px to center it.
*
* Hover:
* - Progress holder becomes 5px
* - Progress handle becomes 15px
* - Progress handle is pulled up 5px to center it
*/
.video-js .vjs-progress-control {
-webkit-box-flex: auto;
-moz-box-flex: auto;
@@ -698,7 +642,6 @@ fonts to show/hide properly.
.vjs-live .vjs-progress-control {
display: none; }
/* Box containing play and load progresses. Also acts as seek scrubber. */
.video-js .vjs-progress-holder {
-webkit-box-flex: auto;
-moz-box-flex: auto;
@@ -711,20 +654,17 @@ fonts to show/hide properly.
transition: all 0.2s;
height: 0.3em; }
/* We need an increased hit area on hover */
.video-js .vjs-progress-control:hover .vjs-progress-holder {
font-size: 1.666666666666666666em; }
/* Also show the current time tooltip */
/* If we let the font size grow as much as everything else, the current time tooltip ends up
ginormous. If you'd like to enable the current time tooltip all the time, this should be disabled
to avoid a weird hitch when you roll off the hover. */
.video-js .vjs-progress-control:hover .vjs-mouse-display:after,
.video-js .vjs-progress-control:hover .vjs-play-progress:after {
display: block;
/* If we let the font size grow as much as everything else, the current time tooltip ends up
ginormous. If you'd like to enable the current time tooltip all the time, this should be disabled
to avoid a weird hitch when you roll off the hover. */
font-size: 0.6em; }
/* 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 {
@@ -733,9 +673,7 @@ fonts to show/hide properly.
height: 0.3em;
margin: 0;
padding: 0;
/* updated by javascript during playback */
width: 0;
/* Needed for IE6 */
left: 0;
top: 0; }
@@ -752,7 +690,6 @@ fonts to show/hide properly.
.video-js .vjs-mouse-display:after,
.video-js .vjs-play-progress:after {
/* By default this is hidden and only shown when hovering over the progress control */
display: none;
position: absolute;
top: -2.4em;
@@ -772,17 +709,11 @@ fonts to show/hide properly.
z-index: 1; }
.video-js .vjs-load-progress {
/* For IE8 we'll lighten the color */
background: ligthen(#73859f, 25%);
/* Otherwise we'll rely on stacked opacities */
background: rgba(115, 133, 159, 0.5); }
/* 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 {
/* For IE8 we'll lighten the color */
background: ligthen(#73859f, 50%);
/* Otherwise we'll rely on stacked opacities */
background: rgba(115, 133, 159, 0.75); }
.video-js.vjs-no-flex .vjs-progress-control {
@@ -892,18 +823,12 @@ specific time ranges that have been buffered */
top: -0.3em;
right: -0.5em; }
/* Assumes volume starts at 1.0. */
.vjs-volume-bar.vjs-slider-vertical .vjs-volume-level {
height: 100%; }
.vjs-volume-bar.vjs-slider-horizontal .vjs-volume-level {
width: 100%; }
/* 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-menu-button-popup.vjs-volume-menu-button .vjs-menu {
display: block;
width: 0;
@@ -911,7 +836,8 @@ width and height to zero. */
border-top-color: transparent; }
.vjs-menu-button-popup.vjs-volume-menu-button-vertical .vjs-menu {
left: 0.5em; }
left: 0.5em;
height: 8em; }
.vjs-menu-button-popup.vjs-volume-menu-button-horizontal .vjs-menu {
left: -2em; }
@@ -933,8 +859,6 @@ width and height to zero. */
width: 8em; }
.vjs-volume-menu-button.vjs-menu-button-inline .vjs-menu-content {
/* An inline volume should never have a menu background color.
This protects it from external changes to background colors. */
background-color: transparent !important; }
.vjs-poster {
@@ -953,7 +877,6 @@ width and height to zero. */
left: 0;
height: 100%; }
/* Used for IE8 fallback */
.vjs-poster img {
display: block;
vertical-align: middle;
@@ -962,20 +885,15 @@ width and height to zero. */
padding: 0;
width: 100%; }
/* Hide the poster after the video has started playing */
.vjs-has-started .vjs-poster {
display: none; }
/* Don't hide the poster if we're playing audio */
.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 */
.vjs-controls-disabled .vjs-poster {
display: none; }
/* Hide the poster when native controls are used otherwise it covers them */
.vjs-using-native-controls .vjs-poster {
display: none; }
@@ -1013,7 +931,6 @@ and the native poster can take over */
.vjs-live .vjs-time-control {
display: none; }
/* We need the extra specificity that referencing .vjs-no-flex provides. */
.video-js .vjs-current-time,
.vjs-no-flex .vjs-current-time {
display: none; }
@@ -1037,7 +954,6 @@ and the native poster can take over */
-ms-flex: none;
flex: none; }
/* Emulated tracks */
.vjs-text-track-display {
position: absolute;
bottom: 3em;
@@ -1046,16 +962,13 @@ and the native poster can take over */
top: 0;
pointer-events: none; }
/* 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) */
background-color: #000;
background-color: rgba(0, 0, 0, 0.5); }
@@ -1068,7 +981,6 @@ and the native poster can take over */
.vjs-tt-cue {
display: block; }
/* Native tracks */
video::-webkit-media-text-track-display {
-moz-transform: translateY(-3em);
-ms-transform: translateY(-3em);
@@ -1076,7 +988,6 @@ video::-webkit-media-text-track-display {
-webkit-transform: translateY(-3em);
transform: translateY(-3em); }
/* Move captions down when controls aren't being shown */
.video-js.vjs-user-inactive.vjs-playing video::-webkit-media-text-track-display {
-moz-transform: translateY(-1.5em);
-ms-transform: translateY(-1.5em);
@@ -1093,7 +1004,6 @@ video::-webkit-media-text-track-display {
-ms-flex: none;
flex: none; }
/* Switch to the exit icon when the player is in fullscreen */
.vjs-playback-rate .vjs-playback-rate-value {
font-size: 1.5em;
line-height: 2;
@@ -1134,7 +1044,6 @@ video::-webkit-media-text-track-display {
left: 50%;
margin: -25px 0 0 -25px;
opacity: 0.85;
/* Need to fix centered page layouts */
text-align: left;
border: 6px solid rgba(43, 51, 63, 0.7);
box-sizing: border-box;
@@ -1156,13 +1065,11 @@ video::-webkit-media-text-track-display {
width: inherit;
height: inherit;
border-radius: inherit;
/* Keep 100% opacity so they don't show through each other */
opacity: 1;
border: inherit;
border-color: transparent;
border-top-color: white; }
/* only animate when showing because it can be processor heavy */
.vjs-seeking .vjs-loading-spinner:before,
.vjs-seeking .vjs-loading-spinner:after,
.vjs-waiting .vjs-loading-spinner:before,
@@ -1214,7 +1121,6 @@ video::-webkit-media-text-track-display {
.vjs-chapters-button .vjs-menu {
left: -10em;
/* (Width of vjs-menu - width of vjs-control) / 2 */
width: 0; }
.vjs-chapters-button .vjs-menu ul {
+1 -1
Ver Arquivo
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
+637 -154
Ver Arquivo
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+17 -13
Ver Arquivo
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
+10 -9
Ver Arquivo
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
+1 -1
Ver Arquivo
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
+1 -1
Ver Arquivo
@@ -9,7 +9,7 @@ Step 1: Include the Video.js Javascript and CSS files in the head of your page.
You can download the Video.js source and host it on your own servers, or use the free CDN hosted version. As of Video.js 5.0, the source is [transpiled from ES2015](http://babeljs.io/) (formerly known as ES6) to [ES5](https://es5.github.io/), but IE8 only supports ES3. In order to continue to support IE8, we've bundled an [ES5 shim and sham](https://github.com/es-shims/es5-shim) together and hosted it on the CDN.
```html
<script src="//vjs.zencdn.net/ie8/1.1.0/videojs-ie8.min.js"></script>
<script src="//vjs.zencdn.net/ie8/1.1.1/videojs-ie8.min.js"></script>
```
### CDN Version ###
+34
Ver Arquivo
@@ -49,6 +49,40 @@ When adding additional Tech to a video player, make sure to add the supported te
techOrder: ["html5", "flash", "other supported tech"]
});
Technology Ordering
==================
By default Video.js performs "Tech-first" ordering when it searches for a source/tech combination to play videos. This means that if you have two sources and two techs, video.js will try to play each video with the first tech in the `techOrder` option property before moving on to try the next playback technology.
Tech-first ordering can present a problem if you have a `sourceHandler` that supports both `Html5` and `Flash` techs such as videojs-contrib-hls.
For example, given the following video element:
<video data-setup='{"techOrder": ["html5", "flash"]}'>
<source src="http://your.static.provider.net/path/to/video.m3u8" type="application/x-mpegURL">
<source src="http://your.static.provider.net/path/to/video.mp4" type="video/mp4">
</video>
There is a good chance that the mp4 source will be selected on platforms that do not have media source extensions. Video.js will try all sources against the first playback technology, in this case `Html5`, and select the first source that can play - in this case MP4.
In "Tech-first" mode, the tests run something like this:
Can video.m3u8 play with Html5? No...
Can video.mp4 play with Html5? Yes! Use the second source.
Video.js now provides another method of selecting the source - "Source-first" ordering. In this mode, Video.js tries the first source against every tech in `techOrder` before moving onto the next source.
With a player setup as follows:
<video data-setup='{"techOrder": ["html5", "flash"], "sourceOrder": true}'>
<source src="http://your.static.provider.net/path/to/video.m3u8" type="application/x-mpegURL">
<source src="http://your.static.provider.net/path/to/video.mp4" type="video/mp4">
</video>
The Flash-based HLS support will be tried before falling back to the MP4 source.
In "Source-first" mode, the tests run something like this:
Can video.m3u8 play with Html5? No...
Can video.m3u8 play with Flash? Yes! Use the first source.
Flash Technology
==================
The Flash playback tech is a part of the default `techOrder`. You may notice undesirable playback behavior in browsers that are subject to using this playback tech, in particular when scrubbing and seeking within a video. This behavior is a result of Flash's progressive video playback.
+2 -2
Ver Arquivo
@@ -1,7 +1,7 @@
{
"name": "video.js",
"description": "An HTML5 and Flash video player with a common API and skin for both.",
"version": "5.2.3",
"version": "5.4.2",
"copyright": "Copyright Brightcove, Inc. <https://www.brightcove.com/>",
"license": "Apache-2.0",
"keywords": [
@@ -29,7 +29,7 @@
"safe-json-parse": "^4.0.0",
"tsml": "1.0.1",
"videojs-font": "1.4.0",
"videojs-ie8": "1.1.0",
"videojs-ie8": "1.1.1",
"videojs-swf": "5.0.1",
"vtt.js": "git+https://github.com/gkatsev/vtt.js.git#vjs-v0.12.1",
"xhr": "~2.2.0"
+1 -1
Ver Arquivo
@@ -12,7 +12,7 @@
opacity: 1;
border: 0.06666em solid $primary-foreground-color;
/* Need a slightly gray bg so it can be seen on black backgrounds */
// Need a slightly gray bg so it can be seen on black backgrounds
@include background-color-with-alpha($primary-background-color, $primary-background-transparency);
@include border-radius(0.3em);
@include transition(all 0.4s);
+1 -1
Ver Arquivo
@@ -3,7 +3,7 @@
}
.vjs-chapters-button .vjs-menu {
left: -10em; /* (Width of vjs-menu - width of vjs-control) / 2 */
left: -10em; // (Width of vjs-menu - width of vjs-control) / 2
width: 0;
}
+6 -7
Ver Arquivo
@@ -32,7 +32,7 @@
.vjs-controls-disabled .vjs-control-bar,
.vjs-using-native-controls .vjs-control-bar,
.vjs-error .vjs-control-bar {
/* !important is ok in this context. */
// !important is ok in this context.
display: none !important;
}
@@ -42,17 +42,16 @@
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
*/
// 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-user-inactive.vjs-playing .vjs-control-bar :before {
@media #{$ie8screen} { content: ""; }
}
/* IE 8 + 9 Support */
// IE 8 + 9 Support
.vjs-has-started.vjs-no-flex .vjs-control-bar {
display: table;
}
+3 -3
Ver Arquivo
@@ -19,19 +19,19 @@
}
}
/* Replacement for focus outline */
// 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-foreground-color, 1);
}
/* Hide control text visually, but have it available for screenreaders */
// Hide control text visually, but have it available for screenreaders
.video-js .vjs-control-text {
@include hide-visually;
}
/* IE 8 + 9 Support */
// IE 8 + 9 Support
.vjs-no-flex .vjs-control {
display: table-cell;
vertical-align: middle;
+1 -1
Ver Arquivo
@@ -6,7 +6,7 @@
.video-js .vjs-fullscreen-control {
@extend .vjs-icon-fullscreen-enter;
}
/* Switch to the exit icon when the player is in fullscreen */
// Switch to the exit icon when the player is in fullscreen
.video-js.vjs-fullscreen .vjs-fullscreen-control {
@extend .vjs-icon-fullscreen-exit;
}
+26 -27
Ver Arquivo
@@ -1,9 +1,8 @@
.video-js {
/* display:inline-block would be closer to the video el's display:inline
* but it results in flash reloading when going into fullscreen [#2205]
*/
// display:inline-block would be closer to the video el's display:inline
// but it results in flash reloading when going into fullscreen [#2205]
display: block;
/* Make video.js videos align top when next to video elements */
// Make video.js videos align top when next to video elements
vertical-align: top;
box-sizing: border-box;
@@ -11,21 +10,21 @@
background-color: #000;
position: relative;
padding: 0;
/* Start with 10px for base font size so other dimensions can be em based and
easily calculable. */
// Start with 10px for base font size so other dimensions can be em based and
// easily calculable.
font-size: 10px;
line-height: 1;
/* Provide some basic defaults for fonts */
// Provide some basic defaults for fonts
font-weight: normal;
font-style: normal;
/* Avoiding helvetica: issue #376 */
// 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. */
// Fix for Firefox 9 fullscreen (only if it is enabled). Not needed when
// checking fullScreenEnabled.
&:-moz-full-screen { position: absolute; }
&:-webkit-full-screen {
@@ -34,35 +33,35 @@
}
}
/* All elements inherit border-box sizing */
// All elements inherit border-box sizing
.video-js *,
.video-js *:before,
.video-js *:after {
box-sizing: inherit;
}
/* List style reset */
// List style reset
.video-js ul {
font-family: inherit;
font-size: inherit;
line-height: inherit;
list-style-position: outside;
/* Important to specify each */
// Important to specify each
margin-left: 0;
margin-right: 0;
margin-top: 0;
margin-bottom: 0;
}
/* Fill the width of the containing element and use padding to create the
desired aspect ratio. Default to 16x9 unless another ratio is given. */
// Fill the width of the containing element and use padding to create the
// desired aspect ratio. Default to 16x9 unless another ratio is given.
@mixin apply-aspect-ratio($width, $height) {
padding-top: 100% * ($height/$width);
}
/* Not including a default AR in vjs-fluid because it would override
the user set AR injected into the header. */
// Not including a default AR in vjs-fluid because it would override
// the user set AR injected into the header.
.video-js.vjs-fluid,
.video-js.vjs-16-9,
.video-js.vjs-4-3 {
@@ -84,8 +83,8 @@
height: 100%;
}
/* Playback technology elements expand to the width/height of the containing div
<video> or <object> */
// Playback technology elements expand to the width/height of the containing div
// <video> or <object>
.video-js .vjs-tech {
position: absolute;
top: 0;
@@ -94,12 +93,12 @@
height: 100%;
}
/* Fullscreen Styles */
// 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 */
// Fix for IE6 full-window. http://www.cssplay.co.uk/layouts/fixed.html
overflow-y: auto;
}
.vjs-full-window .video-js.vjs-fullscreen {
@@ -114,7 +113,7 @@ body.vjs-full-window {
.video-js.vjs-fullscreen {
width: 100% !important;
height: 100% !important;
/* Undo any aspect ratio padding for fluid layouts */
// Undo any aspect ratio padding for fluid layouts
padding-top: 0 !important;
}
.video-js.vjs-fullscreen.vjs-user-inactive {
@@ -122,7 +121,7 @@ body.vjs-full-window {
}
/* Hide disabled or unsupported controls. */
// Hide disabled or unsupported controls.
.vjs-hidden { display: none !important; }
// Visually hidden offscreen, but accessible to screen readers.
@@ -140,10 +139,10 @@ body.vjs-full-window {
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. */
// 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: #fff;
+3 -3
Ver Arquivo
@@ -6,7 +6,7 @@
margin: -25px 0 0 -25px;
opacity: 0.85;
/* Need to fix centered page layouts */
// Need to fix centered page layouts
text-align: left;
border: 6px solid rgba($primary-background-color, $primary-background-transparency);
@@ -33,14 +33,14 @@
width: inherit;
height: inherit;
border-radius: inherit;
/* Keep 100% opacity so they don't show through each other */
// Keep 100% opacity so they don't show through each other
opacity: 1;
border: inherit;
border-color: transparent;
border-top-color: white;
}
/* only animate when showing because it can be processor heavy */
// only animate when showing because it can be processor heavy
.vjs-seeking .vjs-loading-spinner:before,
.vjs-seeking .vjs-loading-spinner:after,
.vjs-waiting .vjs-loading-spinner:before,
+6 -6
Ver Arquivo
@@ -15,7 +15,7 @@
height: 100%;
}
/* Used for IE8 fallback */
// Used for IE8 fallback
.vjs-poster img {
display: block;
vertical-align: middle;
@@ -25,23 +25,23 @@
width: 100%;
}
/* Hide the poster after the video has started playing */
// Hide the poster after the video has started playing
.vjs-has-started .vjs-poster {
display: none;
}
/* Don't hide the poster if we're playing audio */
// Don't hide the poster if we're playing audio
.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 */
// Hide the poster when controls are disabled because it's clickable
// and the native poster can take over
.vjs-controls-disabled .vjs-poster {
display: none;
}
/* Hide the poster when native controls are used otherwise it covers them */
// Hide the poster when native controls are used otherwise it covers them
.vjs-using-native-controls .vjs-poster {
display: none;
}
+30 -30
Ver Arquivo
@@ -1,16 +1,16 @@
/**
* Let's talk pixel math!
* Start with a base font size of 10px (assuming that hasn't changed)
* No Hover:
* - Progress holder is 3px
* - Progress handle is 9px
* - Progress handle is pulled up 3px to center it.
*
* Hover:
* - Progress holder becomes 5px
* - Progress handle becomes 15px
* - Progress handle is pulled up 5px to center it
*/
//
// Let's talk pixel math!
// Start with a base font size of 10px (assuming that hasn't changed)
// No Hover:
// - Progress holder is 3px
// - Progress handle is 9px
// - Progress handle is pulled up 3px to center it.
//
// Hover:
// - Progress holder becomes 5px
// - Progress handle becomes 15px
// - Progress handle is pulled up 5px to center it
//
.video-js .vjs-progress-control {
@include flex(auto);
@@ -21,30 +21,30 @@
display: none;
}
/* Box containing play and load progresses. Also acts as seek scrubber. */
// Box containing play and load progresses. Also acts as seek scrubber.
.video-js .vjs-progress-holder {
@include flex(auto);
@include transition(all 0.2s);
height: 0.3em;
}
/* We need an increased hit area on hover */
// We need an increased hit area on hover
.video-js .vjs-progress-control:hover .vjs-progress-holder {
font-size: 1.666666666666666666em
}
/* Also show the current time tooltip */
/* If we let the font size grow as much as everything else, the current time tooltip ends up
ginormous. If you'd like to enable the current time tooltip all the time, this should be disabled
to avoid a weird hitch when you roll off the hover. */
// Also show the current time tooltip
.video-js .vjs-progress-control:hover .vjs-mouse-display:after,
.video-js .vjs-progress-control:hover .vjs-play-progress:after {
display: block;
/* If we let the font size grow as much as everything else, the current time tooltip ends up
ginormous. If you'd like to enable the current time tooltip all the time, this should be disabled
to avoid a weird hitch when you roll off the hover. */
font-size: 0.6em;
}
/* Progress Bars */
// 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 {
@@ -53,9 +53,9 @@
height: 0.3em;
margin: 0;
padding: 0;
/* updated by javascript during playback */
// updated by javascript during playback
width: 0;
/* Needed for IE6 *///
// Needed for IE6
left: 0;
top: 0;
}
@@ -81,9 +81,9 @@
}
// Current Time "tooltip"
// By default this is hidden and only shown when hovering over the progress control
.video-js .vjs-mouse-display:after,
.video-js .vjs-play-progress:after {
/* By default this is hidden and only shown when hovering over the progress control */
display: none;
position: absolute;
top: -2.4em;
@@ -101,18 +101,18 @@
}
.video-js .vjs-load-progress {
/* For IE8 we'll lighten the color */
// For IE8 we'll lighten the color
background: ligthen($secondary-background-color, 25%);
/* Otherwise we'll rely on stacked opacities */
// Otherwise we'll rely on stacked opacities
background: rgba($secondary-background-color, $secondary-background-transparency);
}
/* there are child elements of the load progress bar that represent the
specific time ranges that have been buffered */
// 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 {
/* For IE8 we'll lighten the color */
// For IE8 we'll lighten the color
background: ligthen($secondary-background-color, 50%);
/* Otherwise we'll rely on stacked opacities */
// Otherwise we'll rely on stacked opacities
background: rgba($secondary-background-color, 0.75);
}
+8 -8
Ver Arquivo
@@ -1,4 +1,4 @@
/* Emulated tracks */
// Emulated tracks
.vjs-text-track-display {
position: absolute;
bottom: 3em;
@@ -8,30 +8,30 @@
pointer-events: none;
}
/* Move captions down when controls aren't being shown */
// Move captions down when controls aren't being shown
.video-js.vjs-user-inactive.vjs-playing .vjs-text-track-display {
bottom: 1em;
}
/* Individual tracks */
// 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) */
// Transparent black background, or fallback to all black (oldIE)
@include background-color-with-alpha(#000, 0.5);
}
.vjs-subtitles { color: #fff /* Subtitles are white */; }
.vjs-captions { color: #fc6 /* Captions are yellow */; }
.vjs-subtitles { color: #fff; } // Subtitles are white
.vjs-captions { color: #fc6; } // Captions are yellow
.vjs-tt-cue { display: block; }
/* Native tracks */
// Native tracks
video::-webkit-media-text-track-display {
@include transform(translateY(-3em));
}
/* Move captions down when controls aren't being shown */
// Move captions down when controls aren't being shown
.video-js.vjs-user-inactive.vjs-playing video::-webkit-media-text-track-display {
@include transform(translateY(-1.5em));
}
+1 -1
Ver Arquivo
@@ -8,7 +8,7 @@
display: none;
}
/* We need the extra specificity that referencing .vjs-no-flex provides. */
// We need the extra specificity that referencing .vjs-no-flex provides.
.video-js .vjs-current-time,
.vjs-no-flex .vjs-current-time {
display: none;
+9 -8
Ver Arquivo
@@ -73,7 +73,7 @@
}
}
/* Assumes volume starts at 1.0. */
// Assumes volume starts at 1.0.
.vjs-volume-bar.vjs-slider-vertical .vjs-volume-level {
height: 100%;
}
@@ -82,11 +82,11 @@
width: 100%;
}
/* 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. */
// 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-menu-button-popup.vjs-volume-menu-button .vjs-menu {
display: block;
width: 0;
@@ -96,6 +96,7 @@ width and height to zero. */
.vjs-menu-button-popup.vjs-volume-menu-button-vertical .vjs-menu {
left: 0.5em;
height: 8em;
}
.vjs-menu-button-popup.vjs-volume-menu-button-horizontal .vjs-menu {
left: -2em;
@@ -123,7 +124,7 @@ width and height to zero. */
}
.vjs-volume-menu-button.vjs-menu-button-inline .vjs-menu-content {
/* An inline volume should never have a menu background color.
This protects it from external changes to background colors. */
// An inline volume should never have a menu background color.
// This protects it from external changes to background colors.
background-color: transparent !important;
}
+5 -5
Ver Arquivo
@@ -3,19 +3,19 @@
position: absolute;
bottom: 0;
width: 10em;
left: -3em; /* (Width of vjs-menu - width of button) / 2 */
left: -3em; // (Width of vjs-menu - width of button) / 2
height: 0em;
margin-bottom: 1.5em;
border-top-color: rgba($primary-background-color, $primary-background-transparency); /* Same as ul background */
border-top-color: rgba($primary-background-color, $primary-background-transparency); // Same as ul background
}
/* Button Pop-up Menu */
.vjs-menu-button-popup .vjs-menu ul {
// Button Pop-up Menu
.vjs-menu-button-popup .vjs-menu .vjs-menu-content {
@include background-color-with-alpha($primary-background-color, $primary-background-transparency);
position: absolute;
width: 100%;
bottom: 1.5em; /* Same bottom as vjs-menu border-top */
bottom: 1.5em; // Same bottom as vjs-menu border-top
max-height: 15em;
}
+1 -1
Ver Arquivo
@@ -8,7 +8,7 @@
overflow: auto;
}
/* prevent menus from opening while scrubbing (FF, IE) */
// prevent menus from opening while scrubbing (FF, IE)
.vjs-scrubbing .vjs-menu-button:hover .vjs-menu {
display: none;
}
@@ -77,21 +77,13 @@ class ChaptersButton extends TextTrackButton {
let chaptersTrack;
let items = this.items = [];
for (let i = 0, l = tracks.length; i < l; i++) {
for (let i = 0, length = tracks.length; i < length; i++) {
let track = tracks[i];
if (track['kind'] === this.kind_) {
if (!track.cues) {
track['mode'] = 'hidden';
/* jshint loopfunc:true */
// TODO see if we can figure out a better way of doing this https://github.com/videojs/video.js/issues/1864
window.setTimeout(Fn.bind(this, function() {
this.createMenu();
}), 100);
/* jshint loopfunc:false */
} else {
chaptersTrack = track;
break;
}
chaptersTrack = track;
break;
}
}
@@ -105,7 +97,17 @@ class ChaptersButton extends TextTrackButton {
}));
}
if (chaptersTrack) {
if (chaptersTrack && chaptersTrack.cues == null) {
chaptersTrack['mode'] = 'hidden';
let remoteTextTrackEl = this.player_.remoteTextTrackEls().getTrackElementByTrack_(chaptersTrack);
if (remoteTextTrackEl) {
remoteTextTrackEl.addEventListener('load', (event) => this.update());
}
}
if (chaptersTrack && chaptersTrack.cues && chaptersTrack.cues.length > 0) {
let cues = chaptersTrack['cues'], cue;
for (let i = 0, l = cues.length; i < l; i++) {
@@ -120,6 +122,7 @@ class ChaptersButton extends TextTrackButton {
menu.addChild(mi);
}
this.addChild(menu);
}
+106 -27
Ver Arquivo
@@ -612,6 +612,30 @@ class Player extends Component {
this.tech_ = false;
}
/**
* Return a reference to the current tech.
* It will only return a reference to the tech if given an object with the
* `IWillNotUseThisInPlugins` property on it. This is try and prevent misuse
* of techs by plugins.
*
* @param {Object}
* @return {Object} The Tech
* @method tech
*/
tech(safety) {
if (safety && safety.IWillNotUseThisInPlugins) {
return this.tech_;
}
let errorText = `
Please make sure that you are not using this inside of a plugin.
To disable this alert and error, please pass in an object with
\`IWillNotUseThisInPlugins\` to the \`tech\` method. See
https://github.com/videojs/video.js/issues/2617 for more info.
`;
window.alert(errorText);
throw new Error(errorText);
}
/**
* Set up click and touch listeners for the playback element
*
@@ -1693,43 +1717,75 @@ class Player extends Component {
}
/**
* Select source based on tech order
* Select source based on tech-order or source-order
* Uses source-order selection if `options.sourceOrder` is truthy. Otherwise,
* defaults to tech-order selection
*
* @param {Array} sources The sources for a media asset
* @return {Object|Boolean} Object of source and tech order, otherwise false
* @method selectSource
*/
selectSource(sources) {
// Loop through each playback technology in the options order
for (var i=0,j=this.options_.techOrder;i<j.length;i++) {
let techName = toTitleCase(j[i]);
let tech = Tech.getTech(techName);
// Support old behavior of techs being registered as components.
// Remove once that deprecated behavior is removed.
if (!tech) {
tech = Component.getComponent(techName);
}
// Check if the current tech is defined before continuing
if (!tech) {
log.error(`The "${techName}" tech is undefined. Skipped browser support check for that tech.`);
continue;
}
// Check if the browser supports this technology
if (tech.isSupported()) {
// Loop through each source object
for (var a=0,b=sources;a<b.length;a++) {
var source = b[a];
// Check if source can be played with this technology
if (tech.canPlaySource(source)) {
return { source: source, tech: techName };
// Get only the techs specified in `techOrder` that exist and are supported by the
// current platform
let techs =
this.options_.techOrder
.map(toTitleCase)
.map((techName) => {
// `Component.getComponent(...)` is for support of old behavior of techs
// being registered as components.
// Remove once that deprecated behavior is removed.
return [techName, Tech.getTech(techName) || Component.getComponent(techName)];
})
.filter(([techName, tech]) => {
// Check if the current tech is defined before continuing
if (tech) {
// Check if the browser supports this technology
return tech.isSupported();
}
}
log.error(`The "${techName}" tech is undefined. Skipped browser support check for that tech.`);
return false;
});
// Iterate over each `innerArray` element once per `outerArray` element and execute
// `tester` with both. If `tester` returns a non-falsy value, exit early and return
// that value.
let findFirstPassingTechSourcePair = function (outerArray, innerArray, tester) {
let found;
outerArray.some((outerChoice) => {
return innerArray.some((innerChoice) => {
found = tester(outerChoice, innerChoice);
if (found) {
return true;
}
});
});
return found;
};
let foundSourceAndTech;
let flip = (fn) => (a, b) => fn(b, a);
let finder = ([techName, tech], source) => {
if (tech.canPlaySource(source)) {
return {source: source, tech: techName};
}
};
// Depending on the truthiness of `options.sourceOrder`, we swap the order of techs and sources
// to select from them based on their priority.
if (this.options_.sourceOrder) {
// Source-first ordering
foundSourceAndTech = findFirstPassingTechSourcePair(sources, techs, flip(finder));
} else {
// Tech-first ordering
foundSourceAndTech = findFirstPassingTechSourcePair(techs, sources, finder);
}
return false;
return foundSourceAndTech || false;
}
/**
@@ -1867,6 +1923,19 @@ class Player extends Component {
return this;
}
/**
* Reset the player. Loads the first tech in the techOrder,
* and calls `reset` on the tech`.
*
* @return {Player} Returns the player
* @method reset
*/
reset() {
this.loadTech_(toTitleCase(this.options_.techOrder[0]), null);
this.techCall_('reset');
return this;
}
/**
* Returns the fully qualified URL of the current source value e.g. http://mysite.com/video.mp4
* Can be used in conjuction with `currentType` to assist in rebuilding the current source object.
@@ -2423,6 +2492,16 @@ class Player extends Component {
return this.tech_ && this.tech_['remoteTextTracks']();
}
/**
* Get an array of remote html track elements
*
* @return {HTMLTrackElement[]}
* @method remoteTextTrackEls
*/
remoteTextTrackEls() {
return this.tech_ && this.tech_['remoteTextTrackEls']();
}
/**
* Add a text track
* In addition to the W3C settings we allow adding additional info through options.
+60 -19
Ver Arquivo
@@ -49,6 +49,7 @@ class Html5 extends Tech {
while (nodesLength--) {
let node = nodes[nodesLength];
let nodeName = node.nodeName.toLowerCase();
if (nodeName === 'track') {
if (!this.featuresNativeTextTracks) {
// Empty video tag tracks so the built-in player doesn't use them also.
@@ -57,6 +58,8 @@ class Html5 extends Tech {
// captions and subtitles. videoElement.textTracks
removeNodes.push(node);
} else {
// store HTMLTrackElement and TextTrack to remote list
this.remoteTextTrackEls().addTrackElement_(node);
this.remoteTextTracks().addTrack_(node.track);
}
}
@@ -486,6 +489,15 @@ class Html5 extends Tech {
this.el_.load();
}
/**
* Reset the tech. Removes all sources and calls `load`.
*
* @method reset
*/
reset() {
Html5.resetMediaElement(this.el_);
}
/**
* Get current source
*
@@ -722,11 +734,11 @@ class Html5 extends Tech {
}
/**
* Creates and returns a remote text track object
* Creates a remote text track object and returns a html track element
*
* @param {Object} options The object should contain values for
* kind, language, label and src (location of the WebVTT file)
* @return {TextTrackObject}
* @return {HTMLTrackElement}
* @method addRemoteTextTrack
*/
addRemoteTextTrack(options={}) {
@@ -734,32 +746,34 @@ class Html5 extends Tech {
return super.addRemoteTextTrack(options);
}
var track = document.createElement('track');
let htmlTrackElement = document.createElement('track');
if (options['kind']) {
track['kind'] = options['kind'];
if (options.kind) {
htmlTrackElement.kind = options.kind;
}
if (options['label']) {
track['label'] = options['label'];
if (options.label) {
htmlTrackElement.label = options.label;
}
if (options['language'] || options['srclang']) {
track['srclang'] = options['language'] || options['srclang'];
if (options.language || options.srclang) {
htmlTrackElement.srclang = options.language || options.srclang;
}
if (options['default']) {
track['default'] = options['default'];
if (options.default) {
htmlTrackElement.default = options.default;
}
if (options['id']) {
track['id'] = options['id'];
if (options.id) {
htmlTrackElement.id = options.id;
}
if (options['src']) {
track['src'] = options['src'];
if (options.src) {
htmlTrackElement.src = options.src;
}
this.el().appendChild(track);
this.el().appendChild(htmlTrackElement);
this.remoteTextTracks().addTrack_(track.track);
// store HTMLTrackElement and TextTrack to remote list
this.remoteTextTrackEls().addTrackElement_(htmlTrackElement);
this.remoteTextTracks().addTrack_(htmlTrackElement.track);
return track;
return htmlTrackElement;
}
/**
@@ -773,8 +787,12 @@ class Html5 extends Tech {
return super.removeRemoteTextTrack(track);
}
var tracks, i;
let tracks, i;
let trackElement = this.remoteTextTrackEls().getTrackElementByTrack_(track);
// remove HTMLTrackElement and TextTrack from remote list
this.remoteTextTrackEls().removeTrackElement_(trackElement);
this.remoteTextTracks().removeTrack_(track);
tracks = this.$$('track');
@@ -1092,6 +1110,29 @@ Html5.disposeMediaElement = function(el){
}
};
Html5.resetMediaElement = function(el){
if (!el) { return; }
let sources = el.querySelectorAll('source');
let i = sources.length;
while (i--) {
el.removeChild(sources[i]);
}
// remove any src reference.
// not setting `src=''` because that throws an error
el.removeAttribute('src');
if (typeof el.load === 'function') {
// wrapping in an iife so it's not deoptimized (#1060#discussion_r10324473)
(function() {
try {
el.load();
} catch (e) {}
})();
}
};
Component.registerComponent('Html5', Html5);
Tech.registerTech('Html5', Html5);
export default Html5;
+47 -12
Ver Arquivo
@@ -5,6 +5,9 @@
*/
import Component from '../component';
import HTMLTrackElement from '../tracks/html-track-element';
import HTMLTrackElementList from '../tracks/html-track-element-list';
import mergeOptions from '../utils/merge-options.js';
import TextTrack from '../tracks/text-track';
import TextTrackList from '../tracks/text-track-list';
import * as Fn from '../utils/fn.js';
@@ -233,6 +236,13 @@ class Tech extends Component {
super.dispose();
}
/**
* Reset the tech. Removes all sources and resets readyState.
*
* @method reset
*/
reset() {}
/**
* When invoked without an argument, returns a MediaError object
* representing the current error state of the player or null if
@@ -321,9 +331,8 @@ class Tech extends Component {
window['WebVTT'] = true;
}
let textTracksChanges = Fn.bind(this, function() {
let updateDisplay = () => this.trigger('texttrackchange');
let updateDisplay = () => this.trigger('texttrackchange');
let textTracksChanges = () => {
updateDisplay();
for (let i = 0; i < tracks.length; i++) {
@@ -333,8 +342,9 @@ class Tech extends Component {
track.addEventListener('cuechange', updateDisplay);
}
}
});
};
textTracksChanges();
tracks.addEventListener('change', textTracksChanges);
this.on('dispose', function() {
@@ -370,6 +380,17 @@ class Tech extends Component {
return this.remoteTextTracks_;
}
/**
* Get remote htmltrackelements
*
* @returns {HTMLTrackElementList}
* @method remoteTextTrackEls
*/
remoteTextTrackEls() {
this.remoteTextTrackEls_ = this.remoteTextTrackEls_ || new HTMLTrackElementList();
return this.remoteTextTrackEls_;
}
/**
* Creates and returns a remote text track object
*
@@ -389,19 +410,28 @@ class Tech extends Component {
}
/**
* Creates and returns a remote text track object
* Creates a remote text track object and returns a emulated html track element
*
* @param {Object} options The object should contain values for
* kind, language, label and src (location of the WebVTT file)
* @return {TextTrackObject}
* @return {HTMLTrackElement}
* @method addRemoteTextTrack
*/
addRemoteTextTrack(options) {
let track = createTrackHelper(this, options.kind, options.label, options.language, options);
this.remoteTextTracks().addTrack_(track);
return {
track: track
};
let track = mergeOptions(options, {
tech: this
});
let htmlTrackElement = new HTMLTrackElement(track);
// store HTMLTrackElement and TextTrack to remote list
this.remoteTextTrackEls().addTrackElement_(htmlTrackElement);
this.remoteTextTracks().addTrack_(htmlTrackElement.track);
// must come after remoteTextTracks()
this.textTracks().addTrack_(htmlTrackElement.track);
return htmlTrackElement;
}
/**
@@ -412,6 +442,11 @@ class Tech extends Component {
*/
removeRemoteTextTrack(track) {
this.textTracks().removeTrack_(track);
let trackElement = this.remoteTextTrackEls().getTrackElementByTrack_(track);
// remove HTMLTrackElement and TextTrack from remote list
this.remoteTextTrackEls().removeTrackElement_(trackElement);
this.remoteTextTracks().removeTrack_(track);
}
@@ -440,7 +475,7 @@ class Tech extends Component {
/*
* Return whether the argument is a Tech or not.
* Can be passed either a Class like `Html5` or a instance like `player.tech_`
*
*
* @param {Object} component An item to check
* @return {Boolean} Whether it is a tech or not
*/
+68
Ver Arquivo
@@ -0,0 +1,68 @@
/**
* @file html-track-element.js
*/
import * as browser from '../utils/browser.js';
import document from 'global/document';
class HtmlTrackElementList {
constructor(trackElements = []) {
let list = this;
if (browser.IS_IE8) {
list = document.createElement('custom');
for (let prop in HtmlTrackElementList.prototype) {
if (prop !== 'constructor') {
list[prop] = HtmlTrackElementList.prototype[prop];
}
}
}
list.trackElements_ = [];
Object.defineProperty(list, 'length', {
get() {
return this.trackElements_.length;
}
});
for (let i = 0, length = trackElements.length; i < length; i++) {
list.addTrackElement_(trackElements[i]);
}
if (browser.IS_IE8) {
return list;
}
}
addTrackElement_(trackElement) {
this.trackElements_.push(trackElement);
}
getTrackElementByTrack_(track) {
let trackElement_;
for (let i = 0, length = this.trackElements_.length; i < length; i++) {
if (track === this.trackElements_[i].track) {
trackElement_ = this.trackElements_[i];
break;
}
}
return trackElement_;
}
removeTrackElement_(trackElement) {
for (let i = 0, length = this.trackElements_.length; i < length; i++) {
if (trackElement === this.trackElements_[i]) {
this.trackElements_.splice(i, 1);
break;
}
}
}
}
export default HtmlTrackElementList;
+97
Ver Arquivo
@@ -0,0 +1,97 @@
import * as browser from '../utils/browser.js';
import document from 'global/document';
import EventTarget from '../event-target';
import TextTrack from '../tracks/text-track';
const NONE = 0;
const LOADING = 1;
const LOADED = 2;
const ERROR = 3;
/**
* https://html.spec.whatwg.org/multipage/embedded-content.html#htmltrackelement
*
* interface HTMLTrackElement : HTMLElement {
* attribute DOMString kind;
* attribute DOMString src;
* attribute DOMString srclang;
* attribute DOMString label;
* attribute boolean default;
*
* const unsigned short NONE = 0;
* const unsigned short LOADING = 1;
* const unsigned short LOADED = 2;
* const unsigned short ERROR = 3;
* readonly attribute unsigned short readyState;
*
* readonly attribute TextTrack track;
* };
*
* @param {Object} options TextTrack configuration
* @class HTMLTrackElement
*/
class HTMLTrackElement extends EventTarget {
constructor(options = {}) {
super();
let readyState,
trackElement = this;
if (browser.IS_IE8) {
trackElement = document.createElement('custom');
for (let prop in HTMLTrackElement.prototype) {
if (prop !== 'constructor') {
trackElement[prop] = HTMLTrackElement.prototype[prop];
}
}
}
let track = new TextTrack(options);
trackElement.kind = track.kind;
trackElement.src = track.src;
trackElement.srclang = track.language;
trackElement.label = track.label;
trackElement.default = track.default;
Object.defineProperty(trackElement, 'readyState', {
get() {
return readyState;
}
});
Object.defineProperty(trackElement, 'track', {
get() {
return track;
}
});
readyState = NONE;
track.addEventListener('loadeddata', function() {
readyState = LOADED;
trackElement.trigger({
type: 'load',
target: trackElement
});
});
if (browser.IS_IE8) {
return trackElement;
}
}
}
HTMLTrackElement.prototype.allowedEvents_ = {
load: 'load'
};
HTMLTrackElement.NONE = NONE;
HTMLTrackElement.LOADING = LOADING;
HTMLTrackElement.LOADED = LOADED;
HTMLTrackElement.ERROR = ERROR;
export default HTMLTrackElement;
+6 -1
Ver Arquivo
@@ -141,7 +141,12 @@ class TextTrackDisplay extends Component {
let i = cues.length;
while (i--) {
let cueDiv = cues[i].displayState;
let cue = cues[i];
if (!cue) {
continue;
}
let cueDiv = cue.displayState;
if (overrides.color) {
cueDiv.firstChild.style.color = overrides.color;
}
+23 -3
Ver Arquivo
@@ -69,6 +69,13 @@ for (let event in TextTrackList.prototype.allowedEvents_) {
TextTrackList.prototype['on' + event] = null;
}
/**
* Add TextTrack from TextTrackList
*
* @param {TextTrack} track
* @method addTrack_
* @private
*/
TextTrackList.prototype.addTrack_ = function(track) {
let index = this.tracks_.length;
if (!(''+index in this)) {
@@ -90,18 +97,31 @@ TextTrackList.prototype.addTrack_ = function(track) {
});
};
/**
* Remove TextTrack from TextTrackList
* NOTE: Be mindful of what is passed in as it may be a HTMLTrackElement
*
* @param {TextTrack} rtrack
* @method removeTrack_
* @private
*/
TextTrackList.prototype.removeTrack_ = function(rtrack) {
let result = null;
let track;
for (let i = 0, l = this.length; i < l; i++) {
track = this[i];
if (track === rtrack) {
if (this[i] === rtrack) {
track = this[i];
this.tracks_.splice(i, 1);
break;
}
}
if (!track) {
return;
}
this.trigger({
type: 'removetrack',
track: track
+25 -14
Ver Arquivo
@@ -45,7 +45,9 @@ let TextTrack = function(options={}) {
tt = document.createElement('custom');
for (let prop in TextTrack.prototype) {
tt[prop] = TextTrack.prototype[prop];
if (prop !== 'constructor') {
tt[prop] = TextTrack.prototype[prop];
}
}
}
@@ -233,24 +235,25 @@ TextTrack.prototype.removeCue = function(removeCue) {
* Downloading stuff happens below this point
*/
var parseCues = function(srcContent, track) {
if (typeof window['WebVTT'] !== 'function') {
//try again a bit later
return window.setTimeout(function() {
parseCues(srcContent, track);
}, 25);
}
let parser = new window.WebVTT.Parser(window, window.vttjs, window.WebVTT.StringDecoder());
let parser = new window['WebVTT']['Parser'](window, window['vttjs'], window['WebVTT']['StringDecoder']());
parser['oncue'] = function(cue) {
parser.oncue = function(cue) {
track.addCue(cue);
};
parser['onparsingerror'] = function(error) {
parser.onparsingerror = function(error) {
log.error(error);
};
parser['parse'](srcContent);
parser['flush']();
parser.onflush = function() {
track.trigger({
type: 'loadeddata',
target: track
});
};
parser.parse(srcContent);
parser.flush();
};
var loadTrack = function(src, track) {
@@ -269,7 +272,15 @@ var loadTrack = function(src, track) {
}
track.loaded_ = true;
parseCues(responseBody, track);
// NOTE: this is only used for the alt/video.novtt.js build
if (typeof window.WebVTT !== 'function') {
window.setTimeout(function() {
parseCues(responseBody, track);
}, 100);
} else {
parseCues(responseBody, track);
}
}));
};
+1
Ver Arquivo
@@ -12,6 +12,7 @@
* @function formatTime
*/
function formatTime(seconds, guide=seconds) {
seconds = seconds < 0 ? 0 : seconds;
let s = Math.floor(seconds % 60);
let m = Math.floor(seconds / 60 % 60);
let h = Math.floor(seconds / 3600);
+1
Ver Arquivo
@@ -61,6 +61,7 @@ test('should be able to access expected player API methods', function() {
// TextTrack methods
ok(player.textTracks, 'textTracks exists');
ok(player.remoteTextTrackEls, 'remoteTextTrackEls exists');
ok(player.remoteTextTracks, 'remoteTextTracks exists');
ok(player.addTextTrack, 'addTextTrack exists');
ok(player.addRemoteTextTrack, 'addRemoteTextTrack exists');
+112
Ver Arquivo
@@ -7,6 +7,9 @@ import MediaError from '../../src/js/media-error.js';
import Html5 from '../../src/js/tech/html5.js';
import TestHelpers from './test-helpers.js';
import document from 'global/document';
import window from 'global/window';
import Tech from '../../src/js/tech/tech.js';
import TechFaker from './tech/tech-faker.js';
q.module('Player', {
'setup': function() {
@@ -408,6 +411,43 @@ test('make sure that controls listeners do not get added too many times', functi
player.dispose();
});
test('should select the proper tech based on the the sourceOrder option',
function() {
let fixture = document.getElementById('qunit-fixture');
let html =
'<video id="example_1">' +
'<source src="fake.foo1" type="video/unsupported-format">' +
'<source src="fake.foo2" type="video/foo-format">' +
'</video>';
// Extend TechFaker to create a tech that plays the only mime-type that TechFaker
// will not play
class PlaysUnsupported extends TechFaker {
constructor(options, handleReady){
super(options, handleReady);
}
// Support ONLY "video/unsupported-format"
static isSupported() { return true; }
static canPlayType(type) { return (type === 'video/unsupported-format' ? 'maybe' : ''); }
static canPlaySource(srcObj) { return srcObj.type === 'video/unsupported-format'; }
}
Tech.registerTech('PlaysUnsupported', PlaysUnsupported);
fixture.innerHTML += html;
let tag = document.getElementById('example_1');
let player = new Player(tag, { techOrder: ['techFaker', 'playsUnsupported'], sourceOrder: true });
equal(player.techName_, 'PlaysUnsupported', 'selected the PlaysUnsupported tech when sourceOrder is truthy');
player.dispose();
fixture.innerHTML += html;
tag = document.getElementById('example_1');
player = new Player(tag, { techOrder: ['techFaker', 'playsUnsupported']});
equal(player.techName_, 'TechFaker', 'selected the TechFaker tech when sourceOrder is falsey');
player.dispose();
});
test('should register players with generated ids', function(){
var fixture, video, player, id;
fixture = document.getElementById('qunit-fixture');
@@ -822,3 +862,75 @@ test('you can clear error in the error event', function() {
log.error.restore();
});
test('Player#tech will return tech given the appropriate input', function() {
let tech_ = {};
let returnedTech = Player.prototype.tech.call({tech_}, {IWillNotUseThisInPlugins: true});
equal(returnedTech, tech_, 'We got back the tech we wanted');
});
test('Player#tech alerts and throws without the appropriate input', function() {
let alertCalled;
let oldAlert = window.alert;
window.alert = () => alertCalled = true;
let tech_ = {};
throws(function() {
Player.prototype.tech.call({tech_});
}, new RegExp('https://github.com/videojs/video.js/issues/2617'),
'we threw an error');
ok(alertCalled, 'we called an alert');
window.alert = oldAlert;
});
test('player#reset loads the Html5 tech and then techCalls reset', function() {
let loadedTech;
let loadedSource;
let techCallMethod;
let testPlayer = {
options_: {
techOrder: ['html5', 'flash'],
},
loadTech_(tech, source) {
loadedTech = tech;
loadedSource = source;
},
techCall_(method) {
techCallMethod = method;
}
};
Player.prototype.reset.call(testPlayer);
equal(loadedTech, 'Html5', 'we loaded the html5 tech');
equal(loadedSource, null, 'with a null source');
equal(techCallMethod, 'reset', 'we then reset the tech');
});
test('player#reset loads the first item in the techOrder and then techCalls reset', function() {
let loadedTech;
let loadedSource;
let techCallMethod;
let testPlayer = {
options_: {
techOrder: ['flash', 'html5'],
},
loadTech_(tech, source) {
loadedTech = tech;
loadedSource = source;
},
techCall_(method) {
techCallMethod = method;
}
};
Player.prototype.reset.call(testPlayer);
equal(loadedTech, 'Flash', 'we loaded the Flash tech');
equal(loadedSource, null, 'with a null source');
equal(techCallMethod, 'reset', 'we then reset the tech');
});
+47
Ver Arquivo
@@ -304,3 +304,50 @@ test('should fire makeup events when a video tag is initialized late', function(
testStates({ networkState: 1, readyState: 3 }, ['loadstart', 'loadedmetadata', 'loadeddata', 'canplay']);
testStates({ networkState: 1, readyState: 4 }, ['loadstart', 'loadedmetadata', 'loadeddata', 'canplay', 'canplaythrough']);
});
test('Html5.resetMediaElement should remove sources and call load', function() {
let selector;
let removedChildren = [];
let removedAttribute;
let loaded;
let children = ['source1', 'source2', 'source3'];
let testEl = {
querySelectorAll(input) {
selector = input;
return children;
},
removeChild(child) {
removedChildren.push(child);
},
removeAttribute(attr) {
removedAttribute = attr;
},
load() {
loaded = true;
}
};
Html5.resetMediaElement(testEl);
equal(selector, 'source', 'we got the source elements from the test el');
deepEqual(removedChildren, children.reverse(), 'we removed the children that were present');
equal(removedAttribute, 'src', 'we removed the src attribute');
ok(loaded, 'we called load on the element');
});
test('Html5#reset calls Html5.resetMediaElement when called', function() {
let oldResetMedia = Html5.resetMediaElement;
let resetEl;
Html5.resetMediaElement = (el) => resetEl = el;
let el = {};
Html5.prototype.reset.call({el_: el});
equal(resetEl, el, 'we called resetMediaElement with the tech\'s el');
Html5.resetMediaElement = oldResetMedia;
});
@@ -0,0 +1,59 @@
import HTMLTrackElement from '../../../src/js/tracks/html-track-element.js';
import HTMLTrackElementList from '../../../src/js/tracks/html-track-element-list.js';
import TextTrack from '../../../src/js/tracks/text-track.js';
let noop = Function.prototype;
let defaultTech = {
textTracks: noop,
on: noop,
off: noop,
currentTime: noop
};
let track1 = new TextTrack({
id: 1,
tech: defaultTech
});
let track2 = new TextTrack({
id: 2,
tech: defaultTech
});
var genericHtmlTrackElements = [{
kind: 'captions',
tech: noop,
track: track1
}, {
kind: 'chapters',
tech: noop,
track: track2
}];
q.module('HTML Track Element List');
test('HTMLTrackElementList\'s length is set correctly', function() {
let htmlTrackElementList = new HTMLTrackElementList(genericHtmlTrackElements);
equal(htmlTrackElementList.length, genericHtmlTrackElements.length, `the length is ${genericHtmlTrackElements.length}`);
});
test('can get html track element by track', function() {
let htmlTrackElementList = new HTMLTrackElementList(genericHtmlTrackElements);
equal(htmlTrackElementList.getTrackElementByTrack_(track1).kind, 'captions', 'track1 has kind of captions');
equal(htmlTrackElementList.getTrackElementByTrack_(track2).kind, 'chapters', 'track2 has kind of captions');
});
test('length is updated when new tracks are added or removed', function() {
let htmlTrackElementList = new HTMLTrackElementList(genericHtmlTrackElements);
htmlTrackElementList.addTrackElement_({tech: noop});
equal(htmlTrackElementList.length, genericHtmlTrackElements.length + 1, `the length is ${genericHtmlTrackElements.length + 1}`);
htmlTrackElementList.addTrackElement_({tech: noop});
equal(htmlTrackElementList.length, genericHtmlTrackElements.length + 2, `the length is ${genericHtmlTrackElements.length + 2}`);
htmlTrackElementList.removeTrackElement_(htmlTrackElementList.getTrackElementByTrack_(track1));
equal(htmlTrackElementList.length, genericHtmlTrackElements.length + 1, `the length is ${genericHtmlTrackElements.length + 1}`);
htmlTrackElementList.removeTrackElement_(htmlTrackElementList.getTrackElementByTrack_(track2));
equal(htmlTrackElementList.length, genericHtmlTrackElements.length, `the length is ${genericHtmlTrackElements.length}`);
});
+81
Ver Arquivo
@@ -0,0 +1,81 @@
import HTMLTrackElement from '../../../src/js/tracks/html-track-element.js';
import TextTrack from '../../../src/js/tracks/text-track.js';
import window from 'global/window';
let noop = Function.prototype;
let defaultTech = {
textTracks: noop,
on: noop,
off: noop,
currentTime: noop
};
q.module('HTML Track Element');
test('html track element requires a tech', function() {
window.throws(
function() {
new HTMLTrackElement();
},
new Error('A tech was not provided.'),
'a tech is required for html track element'
);
});
test('can create a html track element with various properties', function() {
let kind = 'chapters',
label = 'English',
language = 'en',
src = 'http://www.example.com';
let htmlTrackElement = new HTMLTrackElement({
kind,
label,
language,
src,
tech: defaultTech
});
equal(htmlTrackElement.default, undefined, 'we have a default');
equal(htmlTrackElement.kind, kind, 'we have a kind');
equal(htmlTrackElement.label, label, 'we have a label');
equal(htmlTrackElement.readyState, 0, 'we have a readyState');
equal(htmlTrackElement.src, src, 'we have a src');
equal(htmlTrackElement.srclang, language, 'we have a srclang');
equal(htmlTrackElement.track.cues, null, 'we have a track');
});
test('defaults when items not provided', function() {
let htmlTrackElement = new HTMLTrackElement({
tech: defaultTech
});
equal(htmlTrackElement.default, undefined, 'we have a default');
equal(htmlTrackElement.kind, 'subtitles', 'we have a kind');
equal(htmlTrackElement.label, '', 'we have a label');
equal(htmlTrackElement.readyState, 0, 'we have a readyState');
equal(htmlTrackElement.src, undefined, 'we have a src');
equal(htmlTrackElement.srclang, '', 'we have a srclang');
equal(htmlTrackElement.track.cues.length, 0, 'we have a track');
});
test('fires loadeddata when track cues become populated', function() {
let changes = 0,
loadHandler;
loadHandler = function() {
changes++;
};
let htmlTrackElement = new HTMLTrackElement({
tech: noop
});
htmlTrackElement.addEventListener('load', loadHandler);
// trigger loaded cues event
htmlTrackElement.track.trigger('loadeddata');
equal(changes, 1, 'a loadeddata event trigger addEventListener');
equal(htmlTrackElement.readyState, 2, 'readyState is loaded');
});
+1 -1
Ver Arquivo
@@ -166,7 +166,7 @@ test('trigger "change" event when "modechange" is fired on a track', function()
equal(changes, 2, 'two change events should have fired');
});
test('trigger "change" event when mode changes on a TextTracl', function() {
test('trigger "change" event when mode changes on a TextTrack', function() {
var tt = new TextTrack({
tech: {
on: noop
+127 -1
Ver Arquivo
@@ -2,6 +2,7 @@ import ChaptersButton from '../../../src/js/control-bar/text-track-controls/chap
import SubtitlesButton from '../../../src/js/control-bar/text-track-controls/subtitles-button.js';
import CaptionsButton from '../../../src/js/control-bar/text-track-controls/captions-button.js';
import TextTrack from '../../../src/js/tracks/text-track.js';
import TextTrackDisplay from '../../../src/js/tracks/text-track-display.js';
import Html5 from '../../../src/js/tech/html5.js';
import Flash from '../../../src/js/tech/flash.js';
@@ -14,7 +15,14 @@ import document from 'global/document';
import window from 'global/window';
import TechFaker from '../tech/tech-faker.js';
q.module('Tracks');
q.module('Tracks', {
'setup': function() {
this.clock = sinon.useFakeTimers();
},
'teardown': function() {
this.clock.restore();
}
});
test('should place title list item into ul', function() {
var player, chaptersButton;
@@ -342,3 +350,121 @@ if (Html5.supportsNativeTextTracks()) {
emulatedTt.on('addtrack', addtrack);
});
}
test('should check for text track changes when emulating text tracks', function() {
let tech = new Tech();
let numTextTrackChanges = 0;
tech.on('texttrackchange', function() {
numTextTrackChanges++;
});
tech.emulateTextTracks();
equal(numTextTrackChanges, 1, 'we got a texttrackchange event');
});
test('removes cuechange event when text track is hidden for emulated tracks', function() {
let player = TestHelpers.makePlayer();
let tt = new TextTrack({
tech: player.tech_,
mode: 'showing'
});
tt.addCue({
id: '1',
startTime: 2,
endTime: 5
});
player.tech_.textTracks().addTrack_(tt);
player.tech_.emulateTextTracks();
let numTextTrackChanges = 0;
player.tech_.on('texttrackchange', function() {
numTextTrackChanges++;
});
tt.mode = 'showing';
equal(numTextTrackChanges, 1,
'texttrackchange should be called once for mode change');
tt.mode = 'showing';
equal(numTextTrackChanges, 2,
'texttrackchange should be called once for mode change');
player.tech_.currentTime = function() {
return 3;
};
player.tech_.trigger('timeupdate');
equal(numTextTrackChanges, 3,
'texttrackchange should be triggered once for the cuechange');
tt.mode = 'hidden';
equal(numTextTrackChanges, 4,
'texttrackchange should be called once for the mode change');
player.tech_.currentTime = function() {
return 7;
};
player.tech_.trigger('timeupdate');
equal(numTextTrackChanges, 4,
'texttrackchange should be not be called since mode is hidden');
});
test('should return correct remote text track values', function () {
let fixture = document.getElementById('qunit-fixture');
let html = '<video id="example_1" class="video-js" autoplay preload="none">';
html += '<source src="http://google.com" type="video/mp4">';
html += '<source src="http://google.com" type="video/webm">';
html += '<track kind="captions" label="label">';
html += '</video>';
fixture.innerHTML += html;
let tag = document.getElementById('example_1');
let player = TestHelpers.makePlayer({}, tag);
this.clock.tick(1);
equal(player.remoteTextTracks().length, 1, 'add text track via html');
equal(player.remoteTextTrackEls().length, 1, 'add html track element via html');
let htmlTrackElement = player.addRemoteTextTrack({
kind: 'captions',
label: 'label'
});
equal(player.remoteTextTracks().length, 2, 'add text track via method');
equal(player.remoteTextTrackEls().length, 2, 'add html track element via method');
player.removeRemoteTextTrack(htmlTrackElement.track);
equal(player.remoteTextTracks().length, 1, 'remove text track via method');
equal(player.remoteTextTrackEls().length, 1, 'remove html track element via method');
player.dispose();
});
test('should uniformly create html track element when adding text track', function () {
let player = TestHelpers.makePlayer();
let track = {
kind: 'kind',
src: 'src',
language: 'language',
label: 'label',
default: 'default'
};
equal(player.remoteTextTrackEls().length, 0, 'no html text tracks');
let htmlTrackElement = player.addRemoteTextTrack(track);
equal(htmlTrackElement.kind, htmlTrackElement.track.kind, 'verify html track element kind');
equal(htmlTrackElement.src, htmlTrackElement.track.src, 'verify html track element src');
equal(htmlTrackElement.srclang, htmlTrackElement.track.language, 'verify html track element language');
equal(htmlTrackElement.label, htmlTrackElement.track.label, 'verify html track element label');
equal(htmlTrackElement.default, htmlTrackElement.track.default, 'verify html track element default');
equal(player.remoteTextTrackEls().length, 1, 'html track element exist');
equal(player.remoteTextTrackEls().getTrackElementByTrack_(htmlTrackElement.track), htmlTrackElement, 'verify same html track element');
player.dispose();
});
+4
Ver Arquivo
@@ -20,6 +20,10 @@ test('should format time as a string', function(){
// Don't do extra leading zeros for hours
ok(formatTime(1,36000) === '0:00:01');
ok(formatTime(1,360000) === '0:00:01');
// Do not display negative time
ok(formatTime(-1) === '0:00');
ok(formatTime(-1,3600) === '0:00:00');
});
test('should format invalid times as dashes', function(){