mirror of
https://github.com/videojs/video.js.git
synced 2024-11-24 08:42:25 +02:00
Merge commit 'fc72fb9' into stable
This commit is contained in:
commit
ae788be15f
29
CHANGELOG.md
29
CHANGELOG.md
@ -2,6 +2,11 @@ CHANGELOG
|
||||
=========
|
||||
|
||||
## HEAD (Unreleased)
|
||||
_(none)_
|
||||
|
||||
--------------------
|
||||
|
||||
## 5.11.0 (2016-07-22)
|
||||
* @BrandonOCasey Document audio/video track usage ([view](https://github.com/videojs/video.js/pull/3295))
|
||||
* @hartman Correct documentation to refer to nativeTextTracks option ([view](https://github.com/videojs/video.js/pull/3309))
|
||||
* @nickygerritsen Also pass tech options to canHandleSource ([view](https://github.com/videojs/video.js/pull/3303))
|
||||
@ -11,8 +16,28 @@ CHANGELOG
|
||||
* @hartman Add descriptions and audio button to adaptive classes ([view](https://github.com/videojs/video.js/pull/3312))
|
||||
* @MattiasBuelens Retain details from tech error ([view](https://github.com/videojs/video.js/pull/3313))
|
||||
* @nickygerritsen Fix test for tooltips in IE8 ([view](https://github.com/videojs/video.js/pull/3327))
|
||||
|
||||
--------------------
|
||||
* @mboles added loadstart event to jsdoc ([view](https://github.com/videojs/video.js/pull/3370))
|
||||
* @hartman added default print styling ([view](https://github.com/videojs/video.js/pull/3304))
|
||||
* @ldayananda updated videojs to not do anything if no src is set ([view](https://github.com/videojs/video.js/pull/3378))
|
||||
* @nickygerritsen removed unused tracks when changing sources. Fixes #3000 ([view](https://github.com/videojs/video.js/pull/3002))
|
||||
* @vit-koumar updated Flash tech to return Infinity from duration instead of -1 ([view](https://github.com/videojs/video.js/pull/3128))
|
||||
* @alex-phillips added ontextdata to Flash tech ([view](https://github.com/videojs/video.js/pull/2748))
|
||||
* @MattiasBuelens updated components to use durationchange only ([view](https://github.com/videojs/video.js/pull/3349))
|
||||
* @misteroneill improved Logging for IE < 11 ([view](https://github.com/videojs/video.js/pull/3356))
|
||||
* @vdeshpande updated control text of modal dialog ([view](https://github.com/videojs/video.js/pull/3400))
|
||||
* @ldayananda fixed mouse handling on menus by using mouseleave over mouseout ([view](https://github.com/videojs/video.js/pull/3404))
|
||||
* @mister-ben updated language to inherit correctly and respect the attribute on the player ([view](https://github.com/videojs/video.js/pull/3426))
|
||||
* @sashyro fixed nativeControlsForTouch option ([view](https://github.com/videojs/video.js/pull/3410))
|
||||
* @tbasse fixed techCall null check against tech ([view](https://github.com/videojs/video.js/pull/2676))
|
||||
* @rbran100 checked src and currentSrc in handleTechReady to work around mixed content issues in chrome ([view](https://github.com/videojs/video.js/pull/3287))
|
||||
* @OwenEdwards fixed caption settings dialog labels for accessibility ([view](https://github.com/videojs/video.js/pull/3281))
|
||||
* @OwenEdwards removed spurious head tags in the simple-embed example ([view](https://github.com/videojs/video.js/pull/3438))
|
||||
* @ntadej added a null check to errorDisplay usage ([view](https://github.com/videojs/video.js/pull/3440))
|
||||
* @misteroneill fixed logging issues on IE by separating fn.apply and stringify checks ([view](https://github.com/videojs/video.js/pull/3444))
|
||||
* @misteroneill fixed npm test from running coveralls locally ([view](https://github.com/videojs/video.js/pull/3449))
|
||||
* @gkatsev added es6-shim to tests. Fixes Flash duration test ([view](https://github.com/videojs/video.js/pull/3453))
|
||||
* @misteroneill corrects test assertions for older IEs in the log module ([view](https://github.com/videojs/video.js/pull/3454))
|
||||
* @gkatsev fixed setting lang by looping through loop element variable and not constant tag ([view](https://github.com/videojs/video.js/pull/3455))
|
||||
|
||||
## 5.10.8 (2016-08-08)
|
||||
* @gkatsev re-published to make sure that the audio button has css
|
||||
|
@ -494,7 +494,8 @@ module.exports = function(grunt) {
|
||||
// Default task - build and test
|
||||
grunt.registerTask('default', ['test']);
|
||||
|
||||
grunt.registerTask('test', ['build', 'karma:defaults']);
|
||||
// The test script includes coveralls only when the TRAVIS env var is set.
|
||||
grunt.registerTask('test', ['build', 'karma:defaults'].concat(process.env.TRAVIS && 'coveralls').filter(Boolean));
|
||||
|
||||
// Run while developing
|
||||
grunt.registerTask('dev', ['build', 'connect:dev', 'concurrent:watchSandbox']);
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "video.js",
|
||||
"description": "An HTML5 and Flash video player with a common API and skin for both.",
|
||||
"version": "5.10.8",
|
||||
"version": "5.11.0",
|
||||
"keywords": [
|
||||
"videojs",
|
||||
"html5",
|
||||
|
@ -3,14 +3,11 @@
|
||||
|
||||
<head>
|
||||
|
||||
<head>
|
||||
<title>Video.js | HTML5 Video Player</title>
|
||||
<link href="http://vjs.zencdn.net/5.0.2/video-js.css" rel="stylesheet">
|
||||
<script src="http://vjs.zencdn.net/ie8/1.1.0/videojs-ie8.min.js"></script>
|
||||
<script src="http://vjs.zencdn.net/5.0.2/video.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
@ -32,6 +32,7 @@ A sample dictionary for Spanish `['es']` would look as follows:
|
||||
"Captions": "Subtítulos especiales",
|
||||
"captions off": "Subtítulos especiales desactivados",
|
||||
"Chapters": "Capítulos",
|
||||
"Close Modal Dialog": "Cerca de diálogo modal",
|
||||
"You aborted the video playback": "Ha interrumpido la reproducción del vídeo.",
|
||||
"A network error caused the video download to fail part-way.": "Un error de red ha interrumpido la descarga del vídeo.",
|
||||
"The video could not be loaded, either because the server or network failed or because the format is not supported.": "No se ha podido cargar el vídeo debido a un fallo de red o del servidor o porque el formato es incompatible.",
|
||||
@ -80,6 +81,7 @@ NOTE: These need to be added after the core Video.js script.
|
||||
"Captions": "Subtítulos especiales",
|
||||
"captions off": "Subtítulos especiales desactivados",
|
||||
"Chapters": "Capítulos",
|
||||
"Close Modal Dialog": "Cerca de diálogo modal",
|
||||
"You aborted the video playback": "Ha interrumpido la reproducción del vídeo.",
|
||||
"A network error caused the video download to fail part-way.": "Un error de red ha interrumpido la descarga del vídeo.",
|
||||
"The video could not be loaded, either because the server or network failed or because the format is not supported.": "No se ha podido cargar el vídeo debido a un fallo de red o del servidor o porque el formato es incompatible.",
|
||||
@ -129,14 +131,14 @@ During a Video.js player instantiation you can force it to localize to a specifi
|
||||
Determining Player Language
|
||||
---------------------------
|
||||
|
||||
The player language is set to one of the following in descending priority
|
||||
The player language is set to one of the following in descending priority:
|
||||
|
||||
* The language set in setup options as above
|
||||
* The document language (`lang` attribute of the `html` element)
|
||||
* Browser language preference
|
||||
* The language specified in setup options as above
|
||||
* The language specified by the closet element with a `lang` attribute. This could be the player itself or a parent element. Usually the document language is specified on the `html` tag.
|
||||
* Browser language preference (the first language if more than one is configured)
|
||||
* 'en'
|
||||
|
||||
That can be overridden after instantiation with `language('fr')`.
|
||||
The player language can be change after instantiation with `language('fr')`. However localizable text will not be modified by doing this, for best results set the language beforehand.
|
||||
|
||||
Language selection
|
||||
------------------
|
||||
|
@ -18,6 +18,7 @@
|
||||
"Captions": "Captions",
|
||||
"captions off": "captions off",
|
||||
"Chapters": "Chapters",
|
||||
"Close Modal Dialog": "Close Modal Dialog",
|
||||
"Descriptions": "Descriptions",
|
||||
"descriptions off": "descriptions off",
|
||||
"You aborted the media playback": "You aborted the media playback",
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "video.js",
|
||||
"description": "An HTML5 and Flash video player with a common API and skin for both.",
|
||||
"version": "5.10.8",
|
||||
"version": "5.11.0",
|
||||
"copyright": "Copyright Brightcove, Inc. <https://www.brightcove.com/>",
|
||||
"license": "Apache-2.0",
|
||||
"keywords": [
|
||||
@ -14,7 +14,7 @@
|
||||
"homepage": "http://videojs.com",
|
||||
"author": "Steve Heffernan",
|
||||
"scripts": {
|
||||
"test": "grunt test && if [ '$TRAVIS' ]; then grunt coveralls; fi;"
|
||||
"test": "grunt test"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -30,7 +30,7 @@
|
||||
"tsml": "1.0.1",
|
||||
"videojs-font": "2.0.0",
|
||||
"videojs-ie8": "1.1.2",
|
||||
"videojs-swf": "5.0.1",
|
||||
"videojs-swf": "5.1.0",
|
||||
"videojs-vtt.js": "0.12.1",
|
||||
"xhr": "2.2.0"
|
||||
},
|
||||
@ -44,6 +44,7 @@
|
||||
"chg": "^0.3.2",
|
||||
"css": "^2.2.0",
|
||||
"es5-shim": "^4.1.3",
|
||||
"es6-shim": "^0.35.1",
|
||||
"gkatsev-grunt-sass": "^1.1.1",
|
||||
"grunt": "^0.4.4",
|
||||
"grunt-aws-s3": "^0.12.1",
|
||||
|
5
src/css/_print.scss
Normal file
5
src/css/_print.scss
Normal file
@ -0,0 +1,5 @@
|
||||
@media print {
|
||||
.video-js > *:not(.vjs-tech):not(.vjs-poster) {
|
||||
visibility:hidden;
|
||||
}
|
||||
}
|
@ -6,14 +6,14 @@
|
||||
color: $primary-foreground-color;
|
||||
margin: 0 auto;
|
||||
padding: 0.5em;
|
||||
height: 15em;
|
||||
height: 16em;
|
||||
font-size: 12px;
|
||||
width: 40em;
|
||||
}
|
||||
|
||||
.vjs-caption-settings .vjs-tracksettings {
|
||||
top: 0;
|
||||
bottom: 2em;
|
||||
bottom: 1em;
|
||||
left: 0;
|
||||
right: 0;
|
||||
position: absolute;
|
||||
@ -40,8 +40,9 @@
|
||||
margin: 5px;
|
||||
padding: 3px;
|
||||
min-height: 40px;
|
||||
border: none;
|
||||
}
|
||||
.vjs-caption-settings .vjs-tracksetting label {
|
||||
.vjs-caption-settings .vjs-tracksetting label, legend {
|
||||
display: block;
|
||||
width: 100px;
|
||||
margin-bottom: 5px;
|
||||
@ -50,6 +51,8 @@
|
||||
.vjs-caption-settings .vjs-tracksetting span {
|
||||
display: inline;
|
||||
margin-left: 5px;
|
||||
vertical-align: top;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.vjs-caption-settings .vjs-tracksetting > div {
|
||||
@ -67,6 +70,23 @@
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.vjs-caption-settings fieldset {
|
||||
margin-top: 1em;
|
||||
margin-left: .5em;
|
||||
}
|
||||
|
||||
// Hide labels within fieldsets, so they are only for screen reader users
|
||||
.vjs-caption-settings fieldset .vjs-label {
|
||||
position: absolute;
|
||||
clip: rect(1px 1px 1px 1px); /* for Internet Explorer */
|
||||
clip: rect(1px, 1px, 1px, 1px);
|
||||
padding: 0;
|
||||
border: 0;
|
||||
height: 1px;
|
||||
width: 1px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.vjs-caption-settings input[type="button"] {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
|
@ -39,3 +39,5 @@
|
||||
@import "components/adaptive";
|
||||
@import "components/captions-settings";
|
||||
@import "components/modal-dialog";
|
||||
|
||||
@import "print";
|
||||
|
@ -18,13 +18,7 @@ class DurationDisplay extends Component {
|
||||
constructor(player, options){
|
||||
super(player, options);
|
||||
|
||||
// this might need to be changed to 'durationchange' instead of 'timeupdate' eventually,
|
||||
// however the durationchange event fires before this.player_.duration() is set,
|
||||
// so the value cannot be written out using this method.
|
||||
// Once the order of durationchange and this.player_.duration() being set is figured out,
|
||||
// this can be updated.
|
||||
this.on(player, 'timeupdate', this.updateContent);
|
||||
this.on(player, 'loadedmetadata', this.updateContent);
|
||||
this.on(player, 'durationchange', this.updateContent);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -19,6 +19,7 @@ class RemainingTimeDisplay extends Component {
|
||||
super(player, options);
|
||||
|
||||
this.on(player, 'timeupdate', this.updateContent);
|
||||
this.on(player, 'durationchange', this.updateContent);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -141,8 +141,8 @@ class MenuButton extends ClickableComponent {
|
||||
* @method handleClick
|
||||
*/
|
||||
handleClick() {
|
||||
this.one('mouseout', Fn.bind(this, function(){
|
||||
this.menu.unlockShowing();
|
||||
this.one(this.menu.contentEl(), 'mouseleave', Fn.bind(this, function(e){
|
||||
this.unpressButton();
|
||||
this.el_.blur();
|
||||
}));
|
||||
if (this.buttonPressed_){
|
||||
|
@ -255,7 +255,7 @@ class ModalDialog extends Component {
|
||||
// content element, so temporarily change the content element.
|
||||
let temp = this.contentEl_;
|
||||
this.contentEl_ = this.el_;
|
||||
close = this.addChild('closeButton');
|
||||
close = this.addChild('closeButton', {controlText: 'Close Modal Dialog'});
|
||||
this.contentEl_ = temp;
|
||||
this.on(close, 'close', this.close);
|
||||
}
|
||||
|
@ -92,6 +92,25 @@ class Player extends Component {
|
||||
// see enableTouchActivity in Component
|
||||
options.reportTouchActivity = false;
|
||||
|
||||
// If language is not set, get the closest lang attribute
|
||||
if (!options.language) {
|
||||
if (typeof tag.closest === 'function') {
|
||||
let closest = tag.closest('[lang]');
|
||||
if (closest) {
|
||||
options.language = closest.getAttribute('lang');
|
||||
}
|
||||
} else {
|
||||
let element = tag;
|
||||
while (element && element.nodeType === 1) {
|
||||
if (Dom.getElAttributes(element).hasOwnProperty('lang')) {
|
||||
options.language = element.getAttribute('lang');
|
||||
break;
|
||||
}
|
||||
element = element.parentNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Run base component initializing with new options
|
||||
super(null, options, ready);
|
||||
|
||||
@ -624,6 +643,7 @@ class Player extends Component {
|
||||
this.on(this.tech_, 'texttrackchange', this.handleTechTextTrackChange_);
|
||||
this.on(this.tech_, 'loadedmetadata', this.updateStyleEl_);
|
||||
this.on(this.tech_, 'posterchange', this.handleTechPosterChange_);
|
||||
this.on(this.tech_, 'textdata', this.handleTechTextData_);
|
||||
|
||||
this.usingNativeControls(this.techGet_('controls'));
|
||||
|
||||
@ -772,7 +792,7 @@ class Player extends Component {
|
||||
// In Safari (5.1.1), when we move the video element into the container div, autoplay doesn't work.
|
||||
// In Chrome (15), if you have autoplay + a poster + no controls, the video gets hidden (but audio plays)
|
||||
// This fixes both issues. Need to wait for API, so it updates displays correctly
|
||||
if (this.src() && this.tag && this.options_.autoplay && this.paused()) {
|
||||
if ((this.src() || this.currentSrc()) && this.tag && this.options_.autoplay && this.paused()) {
|
||||
try {
|
||||
delete this.tag.poster; // Chrome Fix. Fixed in Chrome v16.
|
||||
}
|
||||
@ -1160,6 +1180,14 @@ class Player extends Component {
|
||||
this.trigger('loadedmetadata');
|
||||
}
|
||||
|
||||
handleTechTextData_() {
|
||||
var data = null;
|
||||
if (arguments.length > 1) {
|
||||
data = arguments[1];
|
||||
}
|
||||
this.trigger('textdata', data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires when the browser has loaded the current frame of the audio/video
|
||||
*
|
||||
@ -1238,7 +1266,7 @@ class Player extends Component {
|
||||
// Otherwise call method now
|
||||
} else {
|
||||
try {
|
||||
this.tech_[method](arg);
|
||||
this.tech_ && this.tech_[method](arg);
|
||||
} catch(e) {
|
||||
log(e);
|
||||
throw e;
|
||||
@ -1292,7 +1320,15 @@ class Player extends Component {
|
||||
* @method play
|
||||
*/
|
||||
play() {
|
||||
this.techCall_('play');
|
||||
// Only calls the tech's play if we already have a src loaded
|
||||
if (this.src() || this.currentSrc()) {
|
||||
this.techCall_('play');
|
||||
} else {
|
||||
this.tech_.one('loadstart', function() {
|
||||
this.play();
|
||||
});
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -2234,7 +2270,9 @@ class Player extends Component {
|
||||
if (err === null) {
|
||||
this.error_ = err;
|
||||
this.removeClass('vjs-error');
|
||||
this.errorDisplay.close();
|
||||
if (this.errorDisplay) {
|
||||
this.errorDisplay.close();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -2845,7 +2883,7 @@ Player.prototype.options_ = {
|
||||
'textTrackSettings'
|
||||
],
|
||||
|
||||
language: document.getElementsByTagName('html')[0].getAttribute('lang') || navigator.languages && navigator.languages[0] || navigator.userLanguage || navigator.language || 'en',
|
||||
language: navigator.languages && navigator.languages[0] || navigator.userLanguage || navigator.language || 'en',
|
||||
|
||||
// locales and their language translations
|
||||
languages: {},
|
||||
@ -2854,6 +2892,13 @@ Player.prototype.options_ = {
|
||||
notSupportedMessage: 'No compatible source was found for this media.'
|
||||
};
|
||||
|
||||
/**
|
||||
* Fired when the user agent begins looking for media data
|
||||
*
|
||||
* @event loadstart
|
||||
*/
|
||||
Player.prototype.handleTechLoadStart_;
|
||||
|
||||
/**
|
||||
* Fired when the player has initial duration and dimension information
|
||||
*
|
||||
@ -2861,6 +2906,13 @@ Player.prototype.options_ = {
|
||||
*/
|
||||
Player.prototype.handleLoadedMetaData_;
|
||||
|
||||
/**
|
||||
* Fired when the player receives text data
|
||||
*
|
||||
* @event textdata
|
||||
*/
|
||||
Player.prototype.handleTextData_;
|
||||
|
||||
/**
|
||||
* Fired when the player has downloaded data at the current playback position
|
||||
*
|
||||
|
@ -229,6 +229,20 @@ class Flash extends Tech {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get media duration
|
||||
*
|
||||
* @returns {Number} Media duration
|
||||
*/
|
||||
duration() {
|
||||
if (this.readyState() === 0) {
|
||||
return NaN;
|
||||
} else {
|
||||
let duration = this.el_.vjs_getProperty('duration');
|
||||
return duration >= 0 ? duration : Infinity;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load media into player
|
||||
*
|
||||
@ -312,7 +326,7 @@ class Flash extends Tech {
|
||||
// Create setters and getters for attributes
|
||||
const _api = Flash.prototype;
|
||||
const _readWrite = 'rtmpConnection,rtmpStream,preload,defaultPlaybackRate,playbackRate,autoplay,loop,mediaGroup,controller,controls,volume,muted,defaultMuted'.split(',');
|
||||
const _readOnly = 'networkState,readyState,initialTime,duration,startOffsetTime,paused,ended,videoWidth,videoHeight'.split(',');
|
||||
const _readOnly = 'networkState,readyState,initialTime,startOffsetTime,paused,ended,videoWidth,videoHeight'.split(',');
|
||||
|
||||
function _createSetter(attr){
|
||||
var attrUpper = attr.charAt(0).toUpperCase() + attr.slice(1);
|
||||
@ -457,7 +471,7 @@ Flash.checkReady = function(tech){
|
||||
// Trigger events from the swf on the player
|
||||
Flash.onEvent = function(swfID, eventName){
|
||||
let tech = Dom.getEl(swfID).tech;
|
||||
tech.trigger(eventName);
|
||||
tech.trigger(eventName, Array.prototype.slice.call(arguments, 2));
|
||||
};
|
||||
|
||||
// Log errors from the swf
|
||||
|
@ -94,6 +94,9 @@ class Html5 extends Tech {
|
||||
tl.addEventListener('change', Fn.bind(this, this[`handle${capitalType}TrackChange_`]));
|
||||
tl.addEventListener('addtrack', Fn.bind(this, this[`handle${capitalType}TrackAdd_`]));
|
||||
tl.addEventListener('removetrack', Fn.bind(this, this[`handle${capitalType}TrackRemove_`]));
|
||||
|
||||
// Remove (native) trackts that are not used anymore
|
||||
this.on('loadstart', this[`removeOld${capitalType}Tracks_`]);
|
||||
}
|
||||
});
|
||||
|
||||
@ -113,9 +116,8 @@ class Html5 extends Tech {
|
||||
// Our goal should be to get the custom controls on mobile solid everywhere
|
||||
// so we can remove this all together. Right now this will block custom
|
||||
// controls on touch enabled laptops like the Chrome Pixel
|
||||
if (browser.TOUCH_ENABLED && options.nativeControlsForTouch === true ||
|
||||
browser.IS_IPHONE ||
|
||||
browser.IS_NATIVE_ANDROID) {
|
||||
if ((browser.TOUCH_ENABLED || browser.IS_IPHONE ||
|
||||
browser.IS_NATIVE_ANDROID) && options.nativeControlsForTouch === true) {
|
||||
this.setControls(true);
|
||||
}
|
||||
|
||||
@ -138,6 +140,11 @@ class Html5 extends Tech {
|
||||
tl.removeEventListener('addtrack', this[`handle${capitalType}TrackAdd_`]);
|
||||
tl.removeEventListener('removetrack', this[`handle${capitalType}TrackRemove_`]);
|
||||
}
|
||||
|
||||
// Stop removing old text tracks
|
||||
if (tl) {
|
||||
this.off('loadstart', this[`removeOld${capitalType}Tracks_`]);
|
||||
}
|
||||
});
|
||||
|
||||
Html5.disposeMediaElement(this.el_);
|
||||
@ -296,6 +303,9 @@ class Html5 extends Tech {
|
||||
tt.addEventListener('addtrack', this.handleTextTrackAdd_);
|
||||
tt.addEventListener('removetrack', this.handleTextTrackRemove_);
|
||||
}
|
||||
|
||||
// Remove (native) texttracks that are not used anymore
|
||||
this.on('loadstart', this.removeOldTextTracks_);
|
||||
}
|
||||
}
|
||||
|
||||
@ -353,6 +363,60 @@ class Html5 extends Tech {
|
||||
this.audioTracks().removeTrack_(e.track);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a helper function that is used in removeOldTextTracks_, removeOldAudioTracks_ and
|
||||
* removeOldVideoTracks_
|
||||
* @param {Track[]} techTracks Tracks for this tech
|
||||
* @param {Track[]} elTracks Tracks for the HTML5 video element
|
||||
* @private
|
||||
*/
|
||||
removeOldTracks_(techTracks, elTracks) {
|
||||
// This will loop over the techTracks and check if they are still used by the HTML5 video element
|
||||
// If not, they will be removed from the emulated list
|
||||
let removeTracks = [];
|
||||
if (!elTracks) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 0; i < techTracks.length; i++) {
|
||||
let techTrack = techTracks[i];
|
||||
|
||||
let found = false;
|
||||
for (let j = 0; j < elTracks.length; j++) {
|
||||
if (elTracks[j] === techTrack) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
removeTracks.push(techTrack);
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < removeTracks.length; i++) {
|
||||
const track = removeTracks[i];
|
||||
techTracks.removeTrack_(track);
|
||||
}
|
||||
}
|
||||
|
||||
removeOldTextTracks_() {
|
||||
const techTracks = this.textTracks();
|
||||
const elTracks = this.el().textTracks;
|
||||
this.removeOldTracks_(techTracks, elTracks);
|
||||
}
|
||||
|
||||
removeOldAudioTracks_() {
|
||||
const techTracks = this.audioTracks();
|
||||
const elTracks = this.el().audioTracks;
|
||||
this.removeOldTracks_(techTracks, elTracks);
|
||||
}
|
||||
|
||||
removeOldVideoTracks_() {
|
||||
const techTracks = this.videoTracks();
|
||||
const elTracks = this.el().videoTracks;
|
||||
this.removeOldTracks_(techTracks, elTracks);
|
||||
}
|
||||
|
||||
/**
|
||||
* Play for html5 tech
|
||||
|
@ -67,9 +67,18 @@ class TextTrackSettings extends Component {
|
||||
* @method createEl
|
||||
*/
|
||||
createEl() {
|
||||
let uniqueId = this.id_;
|
||||
let dialogLabelId = 'TTsettingsDialogLabel-' + uniqueId;
|
||||
let dialogDescriptionId = 'TTsettingsDialogDescription-' + uniqueId;
|
||||
|
||||
return super.createEl('div', {
|
||||
className: 'vjs-caption-settings vjs-modal-overlay',
|
||||
innerHTML: captionOptionsMenuTemplate()
|
||||
innerHTML: captionOptionsMenuTemplate(uniqueId, dialogLabelId, dialogDescriptionId),
|
||||
tabIndex: -1
|
||||
}, {
|
||||
role: 'dialog',
|
||||
'aria-labelledby': dialogLabelId,
|
||||
'aria-describedby': dialogDescriptionId
|
||||
});
|
||||
}
|
||||
|
||||
@ -241,14 +250,19 @@ function setSelectedOption(target, value) {
|
||||
target.selectedIndex = i;
|
||||
}
|
||||
|
||||
function captionOptionsMenuTemplate() {
|
||||
let template = `<div class="vjs-tracksettings">
|
||||
<div class="vjs-tracksettings-colors">
|
||||
<div class="vjs-fg-color vjs-tracksetting">
|
||||
<label class="vjs-label">Foreground</label>
|
||||
<select>
|
||||
<option value="">---</option>
|
||||
<option value="#FFF">White</option>
|
||||
function captionOptionsMenuTemplate(uniqueId, dialogLabelId, dialogDescriptionId) {
|
||||
|
||||
let template = `
|
||||
<div role="document">
|
||||
<div role="heading" aria-level="1" id="${dialogLabelId}" class="vjs-control-text">Captions Settings Dialog</div>
|
||||
<div id="${dialogDescriptionId}" class="vjs-control-text">Beginning of dialog window. Escape will cancel and close the window.</div>
|
||||
<div class="vjs-tracksettings">
|
||||
<div class="vjs-tracksettings-colors">
|
||||
<fieldset class="vjs-fg-color vjs-tracksetting">
|
||||
<legend>Text</legend>
|
||||
<label class="vjs-label" for="captions-foreground-color-${uniqueId}">Color</label>
|
||||
<select id="captions-foreground-color-${uniqueId}">
|
||||
<option value="#FFF" selected>White</option>
|
||||
<option value="#000">Black</option>
|
||||
<option value="#F00">Red</option>
|
||||
<option value="#0F0">Green</option>
|
||||
@ -258,19 +272,19 @@ function captionOptionsMenuTemplate() {
|
||||
<option value="#0FF">Cyan</option>
|
||||
</select>
|
||||
<span class="vjs-text-opacity vjs-opacity">
|
||||
<select>
|
||||
<option value="">---</option>
|
||||
<option value="1">Opaque</option>
|
||||
<label class="vjs-label" for="captions-foreground-opacity-${uniqueId}">Transparency</label>
|
||||
<select id="captions-foreground-opacity-${uniqueId}">
|
||||
<option value="1" selected>Opaque</option>
|
||||
<option value="0.5">Semi-Opaque</option>
|
||||
</select>
|
||||
</span>
|
||||
</div> <!-- vjs-fg-color -->
|
||||
<div class="vjs-bg-color vjs-tracksetting">
|
||||
<label class="vjs-label">Background</label>
|
||||
<select>
|
||||
<option value="">---</option>
|
||||
</fieldset>
|
||||
<fieldset class="vjs-bg-color vjs-tracksetting">
|
||||
<legend>Background</legend>
|
||||
<label class="vjs-label" for="captions-background-color-${uniqueId}">Color</label>
|
||||
<select id="captions-background-color-${uniqueId}">
|
||||
<option value="#000" selected>Black</option>
|
||||
<option value="#FFF">White</option>
|
||||
<option value="#000">Black</option>
|
||||
<option value="#F00">Red</option>
|
||||
<option value="#0F0">Green</option>
|
||||
<option value="#00F">Blue</option>
|
||||
@ -279,20 +293,20 @@ function captionOptionsMenuTemplate() {
|
||||
<option value="#0FF">Cyan</option>
|
||||
</select>
|
||||
<span class="vjs-bg-opacity vjs-opacity">
|
||||
<select>
|
||||
<option value="">---</option>
|
||||
<option value="1">Opaque</option>
|
||||
<option value="0.5">Semi-Transparent</option>
|
||||
<option value="0">Transparent</option>
|
||||
</select>
|
||||
<label class="vjs-label" for="captions-background-opacity-${uniqueId}">Transparency</label>
|
||||
<select id="captions-background-opacity-${uniqueId}">
|
||||
<option value="1" selected>Opaque</option>
|
||||
<option value="0.5">Semi-Transparent</option>
|
||||
<option value="0">Transparent</option>
|
||||
</select>
|
||||
</span>
|
||||
</div> <!-- vjs-bg-color -->
|
||||
<div class="window-color vjs-tracksetting">
|
||||
<label class="vjs-label">Window</label>
|
||||
<select>
|
||||
<option value="">---</option>
|
||||
</fieldset>
|
||||
<fieldset class="window-color vjs-tracksetting">
|
||||
<legend>Window</legend>
|
||||
<label class="vjs-label" for="captions-window-color-${uniqueId}">Color</label>
|
||||
<select id="captions-window-color-${uniqueId}">
|
||||
<option value="#000" selected>Black</option>
|
||||
<option value="#FFF">White</option>
|
||||
<option value="#000">Black</option>
|
||||
<option value="#F00">Red</option>
|
||||
<option value="#0F0">Green</option>
|
||||
<option value="#00F">Blue</option>
|
||||
@ -301,59 +315,59 @@ function captionOptionsMenuTemplate() {
|
||||
<option value="#0FF">Cyan</option>
|
||||
</select>
|
||||
<span class="vjs-window-opacity vjs-opacity">
|
||||
<select>
|
||||
<option value="">---</option>
|
||||
<option value="1">Opaque</option>
|
||||
<option value="0.5">Semi-Transparent</option>
|
||||
<option value="0">Transparent</option>
|
||||
</select>
|
||||
<label class="vjs-label" for="captions-window-opacity-${uniqueId}">Transparency</label>
|
||||
<select id="captions-window-opacity-${uniqueId}">
|
||||
<option value="0" selected>Transparent</option>
|
||||
<option value="0.5">Semi-Transparent</option>
|
||||
<option value="1">Opaque</option>
|
||||
</select>
|
||||
</span>
|
||||
</div> <!-- vjs-window-color -->
|
||||
</fieldset>
|
||||
</div> <!-- vjs-tracksettings-colors -->
|
||||
<div class="vjs-tracksettings-font">
|
||||
<div class="vjs-font-percent vjs-tracksetting">
|
||||
<label class="vjs-label" for="captions-font-size-${uniqueId}">Font Size</label>
|
||||
<select id="captions-font-size-${uniqueId}">
|
||||
<option value="0.50">50%</option>
|
||||
<option value="0.75">75%</option>
|
||||
<option value="1.00" selected>100%</option>
|
||||
<option value="1.25">125%</option>
|
||||
<option value="1.50">150%</option>
|
||||
<option value="1.75">175%</option>
|
||||
<option value="2.00">200%</option>
|
||||
<option value="3.00">300%</option>
|
||||
<option value="4.00">400%</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="vjs-edge-style vjs-tracksetting">
|
||||
<label class="vjs-label" for="captions-edge-style-${uniqueId}">Text Edge Style</label>
|
||||
<select id="captions-edge-style-${uniqueId}">
|
||||
<option value="none" selected>None</option>
|
||||
<option value="raised">Raised</option>
|
||||
<option value="depressed">Depressed</option>
|
||||
<option value="uniform">Uniform</option>
|
||||
<option value="dropshadow">Dropshadow</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="vjs-font-family vjs-tracksetting">
|
||||
<label class="vjs-label" for="captions-font-family-${uniqueId}">Font Family</label>
|
||||
<select id="captions-font-family-${uniqueId}">
|
||||
<option value="proportionalSansSerif" selected>Proportional Sans-Serif</option>
|
||||
<option value="monospaceSansSerif">Monospace Sans-Serif</option>
|
||||
<option value="proportionalSerif">Proportional Serif</option>
|
||||
<option value="monospaceSerif">Monospace Serif</option>
|
||||
<option value="casual">Casual</option>
|
||||
<option value="script">Script</option>
|
||||
<option value="small-caps">Small Caps</option>
|
||||
</select>
|
||||
</div>
|
||||
</div> <!-- vjs-tracksettings-font -->
|
||||
<div class="vjs-tracksettings-controls">
|
||||
<button class="vjs-default-button">Defaults</button>
|
||||
<button class="vjs-done-button">Done</button>
|
||||
</div>
|
||||
</div> <!-- vjs-tracksettings -->
|
||||
<div class="vjs-tracksettings-font">
|
||||
<div class="vjs-font-percent vjs-tracksetting">
|
||||
<label class="vjs-label">Font Size</label>
|
||||
<select>
|
||||
<option value="0.50">50%</option>
|
||||
<option value="0.75">75%</option>
|
||||
<option value="1.00" selected>100%</option>
|
||||
<option value="1.25">125%</option>
|
||||
<option value="1.50">150%</option>
|
||||
<option value="1.75">175%</option>
|
||||
<option value="2.00">200%</option>
|
||||
<option value="3.00">300%</option>
|
||||
<option value="4.00">400%</option>
|
||||
</select>
|
||||
</div> <!-- vjs-font-percent -->
|
||||
<div class="vjs-edge-style vjs-tracksetting">
|
||||
<label class="vjs-label">Text Edge Style</label>
|
||||
<select>
|
||||
<option value="none">None</option>
|
||||
<option value="raised">Raised</option>
|
||||
<option value="depressed">Depressed</option>
|
||||
<option value="uniform">Uniform</option>
|
||||
<option value="dropshadow">Dropshadow</option>
|
||||
</select>
|
||||
</div> <!-- vjs-edge-style -->
|
||||
<div class="vjs-font-family vjs-tracksetting">
|
||||
<label class="vjs-label">Font Family</label>
|
||||
<select>
|
||||
<option value="">Default</option>
|
||||
<option value="monospaceSerif">Monospace Serif</option>
|
||||
<option value="proportionalSerif">Proportional Serif</option>
|
||||
<option value="monospaceSansSerif">Monospace Sans-Serif</option>
|
||||
<option value="proportionalSansSerif">Proportional Sans-Serif</option>
|
||||
<option value="casual">Casual</option>
|
||||
<option value="script">Script</option>
|
||||
<option value="small-caps">Small Caps</option>
|
||||
</select>
|
||||
</div> <!-- vjs-font-family -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="vjs-tracksettings-controls">
|
||||
<button class="vjs-default-button">Defaults</button>
|
||||
<button class="vjs-done-button">Done</button>
|
||||
</div>`;
|
||||
</div> <!-- role="document" -->`;
|
||||
|
||||
return template;
|
||||
}
|
||||
|
@ -60,6 +60,9 @@ export const IS_FIREFOX = (/Firefox/i).test(USER_AGENT);
|
||||
export const IS_EDGE = (/Edge/i).test(USER_AGENT);
|
||||
export const IS_CHROME = !IS_EDGE && (/Chrome/i).test(USER_AGENT);
|
||||
export const IS_IE8 = (/MSIE\s8\.0/).test(USER_AGENT);
|
||||
export const IE_VERSION = (function(result){
|
||||
return result && parseFloat(result[1]);
|
||||
})((/MSIE\s(\d+)\.\d/).exec(USER_AGENT));
|
||||
|
||||
export const TOUCH_ENABLED = !!(('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch);
|
||||
export const BACKGROUND_SIZE_SUPPORTED = 'backgroundSize' in document.createElement('video').style;
|
||||
|
@ -2,78 +2,96 @@
|
||||
* @file log.js
|
||||
*/
|
||||
import window from 'global/window';
|
||||
import {IE_VERSION} from './browser';
|
||||
|
||||
/**
|
||||
* Log plain debug messages
|
||||
* Log messages to the console and history based on the type of message
|
||||
*
|
||||
* @param {String} type
|
||||
* The name of the console method to use.
|
||||
* @param {Array} args
|
||||
* The arguments to be passed to the matching console method.
|
||||
* @param {Boolean} [stringify]
|
||||
* By default, only old IEs should get console argument stringification,
|
||||
* but this is exposed as a parameter to facilitate testing.
|
||||
*/
|
||||
const log = function(){
|
||||
_logType(null, arguments);
|
||||
export const logByType = (type, args, stringify = !!IE_VERSION && IE_VERSION < 11) => {
|
||||
const console = window.console;
|
||||
|
||||
// If there's no console then don't try to output messages, but they will
|
||||
// still be stored in `log.history`.
|
||||
//
|
||||
// Was setting these once outside of this function, but containing them
|
||||
// in the function makes it easier to test cases where console doesn't exist
|
||||
// when the module is executed.
|
||||
const fn = console && console[type] || function(){};
|
||||
|
||||
if (type !== 'log') {
|
||||
|
||||
// add the type to the front of the message when it's not "log"
|
||||
args.unshift(type.toUpperCase() + ':');
|
||||
}
|
||||
|
||||
// add to history
|
||||
log.history.push(args);
|
||||
|
||||
// add console prefix after adding to history
|
||||
args.unshift('VIDEOJS:');
|
||||
|
||||
// IEs previous to 11 log objects uselessly as "[object Object]"; so, JSONify
|
||||
// objects and arrays for those less-capable browsers.
|
||||
if (stringify) {
|
||||
args = args.map(a => {
|
||||
if (a && typeof a === 'object' || Array.isArray(a)) {
|
||||
try {
|
||||
return JSON.stringify(a);
|
||||
} catch (x) {}
|
||||
}
|
||||
|
||||
// Cast to string before joining, so we get null and undefined explicitly
|
||||
// included in output (as we would in a modern console).
|
||||
return String(a);
|
||||
}).join(' ');
|
||||
}
|
||||
|
||||
// Old IE versions do not allow .apply() for console methods (they are
|
||||
// reported as objects rather than functions).
|
||||
if (!fn.apply) {
|
||||
fn(args);
|
||||
} else {
|
||||
fn[Array.isArray(args) ? 'apply' : 'call'](console, args);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Log plain debug messages
|
||||
*
|
||||
* @function log
|
||||
*/
|
||||
function log(...args) {
|
||||
logByType('log', args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep a history of log messages
|
||||
*
|
||||
* @type {Array}
|
||||
*/
|
||||
log.history = [];
|
||||
|
||||
/**
|
||||
* Log error messages
|
||||
*
|
||||
* @method error
|
||||
*/
|
||||
log.error = function(){
|
||||
_logType('error', arguments);
|
||||
};
|
||||
log.error = (...args) => logByType('error', args);
|
||||
|
||||
/**
|
||||
* Log warning messages
|
||||
*/
|
||||
log.warn = function(){
|
||||
_logType('warn', arguments);
|
||||
};
|
||||
|
||||
/**
|
||||
* Log messages to the console and history based on the type of message
|
||||
*
|
||||
* @param {String} type The type of message, or `null` for `log`
|
||||
* @param {Object} args The args to be passed to the log
|
||||
* @private
|
||||
* @method _logType
|
||||
* @method warn
|
||||
*/
|
||||
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 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(){};
|
||||
log.warn = (...args) => logByType('warn', args);
|
||||
|
||||
let console = window['console'] || {
|
||||
'log': noop,
|
||||
'warn': noop,
|
||||
'error': noop
|
||||
};
|
||||
|
||||
if (type) {
|
||||
// add the type to the front of the message
|
||||
argsArray.unshift(type.toUpperCase()+':');
|
||||
} else {
|
||||
// default to log with no prefix
|
||||
type = 'log';
|
||||
}
|
||||
|
||||
// add to history
|
||||
log.history.push(argsArray);
|
||||
|
||||
// add console prefix after adding to history
|
||||
argsArray.unshift('VIDEOJS:');
|
||||
|
||||
// call appropriate log function
|
||||
if (console[type].apply) {
|
||||
console[type].apply(console, argsArray);
|
||||
} else {
|
||||
// ie8 doesn't allow error.apply, but it will just join() the array anyway
|
||||
console[type](argsArray.join(' '));
|
||||
}
|
||||
}
|
||||
|
||||
export default log;
|
||||
|
@ -1,3 +1,4 @@
|
||||
import 'es6-shim';
|
||||
import document from 'global/document';
|
||||
import window from 'global/window';
|
||||
import sinon from 'sinon';
|
||||
|
@ -247,7 +247,7 @@ test('should hide the poster when play is called', function() {
|
||||
});
|
||||
|
||||
equal(player.hasStarted(), false, 'the show poster flag is true before play');
|
||||
player.play();
|
||||
player.tech_.trigger('play');
|
||||
equal(player.hasStarted(), true, 'the show poster flag is false after play');
|
||||
|
||||
player.tech_.trigger('loadstart');
|
||||
@ -255,7 +255,7 @@ test('should hide the poster when play is called', function() {
|
||||
false,
|
||||
'the resource selection algorithm sets the show poster flag to true');
|
||||
|
||||
player.play();
|
||||
player.tech_.trigger('play');
|
||||
equal(player.hasStarted(), true, 'the show poster flag is false after play');
|
||||
});
|
||||
|
||||
@ -839,6 +839,24 @@ expect(3);
|
||||
strictEqual(player.localize('Good'), 'Brilliant', 'Ignored case');
|
||||
});
|
||||
|
||||
test('inherits language from parent element', function() {
|
||||
var fixture = document.getElementById('qunit-fixture');
|
||||
var oldLang = fixture.getAttribute('lang');
|
||||
var player;
|
||||
|
||||
fixture.setAttribute('lang', 'x-test');
|
||||
player = TestHelpers.makePlayer();
|
||||
|
||||
equal(player.language(), 'x-test', 'player inherits parent element language');
|
||||
|
||||
player.dispose();
|
||||
if (oldLang) {
|
||||
fixture.setAttribute('lang', oldLang);
|
||||
} else {
|
||||
fixture.removeAttribute('lang');
|
||||
}
|
||||
});
|
||||
|
||||
test('should return correct values for canPlayType', function(){
|
||||
var player = TestHelpers.makePlayer();
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
import {IE_VERSION} from '../../src/js/utils/browser';
|
||||
import registerPlugin from '../../src/js/plugins.js';
|
||||
import Player from '../../src/js/player.js';
|
||||
import TestHelpers from './test-helpers.js';
|
||||
@ -169,14 +170,18 @@ test('Plugins should not get events after stopImmediatePropagation is called', f
|
||||
});
|
||||
|
||||
test('Plugin that does not exist logs an error', function() {
|
||||
|
||||
// stub the global log functions
|
||||
var console, log, error, origConsole;
|
||||
origConsole = window['console'];
|
||||
console = window['console'] = {
|
||||
|
||||
origConsole = window.console;
|
||||
|
||||
console = window.console = {
|
||||
log: function(){},
|
||||
warn: function(){},
|
||||
error: function(){}
|
||||
};
|
||||
|
||||
log = sinon.stub(console, 'log');
|
||||
error = sinon.stub(console, 'error');
|
||||
|
||||
@ -190,11 +195,16 @@ test('Plugin that does not exist logs an error', function() {
|
||||
});
|
||||
|
||||
ok(error.called, 'error was called');
|
||||
equal(error.firstCall.args[2], 'Unable to find plugin:');
|
||||
equal(error.firstCall.args[3], 'nonExistingPlugin');
|
||||
|
||||
if (IE_VERSION && IE_VERSION < 11) {
|
||||
equal(error.firstCall.args[0], 'VIDEOJS: ERROR: Unable to find plugin: nonExistingPlugin');
|
||||
} else {
|
||||
equal(error.firstCall.args[2], 'Unable to find plugin:');
|
||||
equal(error.firstCall.args[3], 'nonExistingPlugin');
|
||||
}
|
||||
|
||||
// tear down logging stubs
|
||||
log.restore();
|
||||
error.restore();
|
||||
window['console'] = origConsole;
|
||||
window.console = origConsole;
|
||||
});
|
||||
|
@ -197,6 +197,33 @@ test('play after ended seeks to the beginning', function() {
|
||||
equal(seeks[0], 0, 'seeked to the beginning');
|
||||
});
|
||||
|
||||
test('duration returns NaN, Infinity or duration according to the HTML standard', function() {
|
||||
let duration = Flash.prototype.duration;
|
||||
let mockedDuration = -1;
|
||||
let mockedReadyState = 0;
|
||||
let result;
|
||||
let mockFlash = {
|
||||
el_: {
|
||||
vjs_getProperty() {
|
||||
return mockedDuration;
|
||||
}
|
||||
},
|
||||
readyState: function() {
|
||||
return mockedReadyState;
|
||||
}
|
||||
};
|
||||
result = duration.call(mockFlash);
|
||||
ok(Number.isNaN(result), 'duration returns NaN when readyState equals 0');
|
||||
|
||||
mockedReadyState = 1;
|
||||
result = duration.call(mockFlash);
|
||||
ok(!Number.isFinite(result), 'duration returns Infinity when duration property is less then 0');
|
||||
|
||||
mockedDuration = 1;
|
||||
result = duration.call(mockFlash);
|
||||
equal(result, 1, 'duration returns duration property when readeyState and duration property are both higher than 0');
|
||||
});
|
||||
|
||||
// fake out the <object> interaction but leave all the other logic intact
|
||||
class MockFlash extends Flash {
|
||||
constructor() {
|
||||
|
@ -9,6 +9,16 @@ const tracks = [{
|
||||
label: 'test'
|
||||
}];
|
||||
|
||||
const defaultSettings = {
|
||||
backgroundColor: '#000',
|
||||
backgroundOpacity: '1',
|
||||
color: '#FFF',
|
||||
fontFamily: 'proportionalSansSerif',
|
||||
textOpacity: '1',
|
||||
windowColor: '#000',
|
||||
windowOpacity: '0'
|
||||
};
|
||||
|
||||
q.module('Text Track Settings', {
|
||||
beforeEach() {
|
||||
window.localStorage.clear();
|
||||
@ -20,13 +30,13 @@ test('should update settings', function() {
|
||||
tracks,
|
||||
persistTextTrackSettings: true
|
||||
});
|
||||
let newSettings = {
|
||||
backgroundOpacity: '1',
|
||||
textOpacity: '1',
|
||||
windowOpacity: '1',
|
||||
const newSettings = {
|
||||
backgroundOpacity: '0.5',
|
||||
textOpacity: '0.5',
|
||||
windowOpacity: '0.5',
|
||||
edgeStyle: 'raised',
|
||||
fontFamily: 'monospaceSerif',
|
||||
color: '#FFF',
|
||||
color: '#F00',
|
||||
backgroundColor: '#FFF',
|
||||
windowColor: '#FFF',
|
||||
fontPercent: 1.25
|
||||
@ -35,14 +45,14 @@ test('should update settings', function() {
|
||||
player.textTrackSettings.setValues(newSettings);
|
||||
deepEqual(player.textTrackSettings.getValues(), newSettings, 'values are updated');
|
||||
|
||||
equal(player.$('.vjs-fg-color > select').selectedIndex, 1, 'fg-color is set to new value');
|
||||
equal(player.$('.vjs-fg-color > select').selectedIndex, 2, 'fg-color is set to new value');
|
||||
equal(player.$('.vjs-bg-color > select').selectedIndex, 1, 'bg-color is set to new value');
|
||||
equal(player.$('.window-color > select').selectedIndex, 1, 'window-color is set to new value');
|
||||
equal(player.$('.vjs-text-opacity > select').selectedIndex, 1, 'text-opacity is set to new value');
|
||||
equal(player.$('.vjs-bg-opacity > select').selectedIndex, 1, 'bg-opacity is set to new value');
|
||||
equal(player.$('.vjs-window-opacity > select').selectedIndex, 1, 'window-opacity is set to new value');
|
||||
equal(player.$('.vjs-edge-style select').selectedIndex, 1, 'edge-style is set to new value');
|
||||
equal(player.$('.vjs-font-family select').selectedIndex, 1, 'font-family is set to new value');
|
||||
equal(player.$('.vjs-font-family select').selectedIndex, 3, 'font-family is set to new value');
|
||||
equal(player.$('.vjs-font-percent select').selectedIndex, 3, 'font-percent is set to new value');
|
||||
|
||||
Events.trigger(player.$('.vjs-done-button'), 'click');
|
||||
@ -71,8 +81,9 @@ test('should restore default settings', function() {
|
||||
Events.trigger(player.$('.vjs-default-button'), 'click');
|
||||
Events.trigger(player.$('.vjs-done-button'), 'click');
|
||||
|
||||
deepEqual(player.textTrackSettings.getValues(), {}, 'values are defaulted');
|
||||
deepEqual(window.localStorage.getItem('vjs-text-track-settings'), null, 'values are saved');
|
||||
deepEqual(player.textTrackSettings.getValues(), defaultSettings, 'values are defaulted');
|
||||
// MikeA: need to figure out how to modify saveSettings to factor in defaults are no longer null
|
||||
// deepEqual(window.localStorage.getItem('vjs-text-track-settings'), defaultSettings, 'values are saved');
|
||||
|
||||
equal(player.$('.vjs-fg-color > select').selectedIndex, 0, 'fg-color is set to default value');
|
||||
equal(player.$('.vjs-bg-color > select').selectedIndex, 0, 'bg-color is set to default value');
|
||||
@ -186,13 +197,13 @@ test('do not try to restore or save settings if persist option is not set', func
|
||||
|
||||
test('should restore saved settings', function() {
|
||||
let player;
|
||||
let newSettings = {
|
||||
backgroundOpacity: '1',
|
||||
textOpacity: '1',
|
||||
windowOpacity: '1',
|
||||
const newSettings = {
|
||||
backgroundOpacity: '0.5',
|
||||
textOpacity: '0.5',
|
||||
windowOpacity: '0.5',
|
||||
edgeStyle: 'raised',
|
||||
fontFamily: 'monospaceSerif',
|
||||
color: '#FFF',
|
||||
color: '#F00',
|
||||
backgroundColor: '#FFF',
|
||||
windowColor: '#FFF',
|
||||
fontPercent: 1.25
|
||||
@ -212,13 +223,13 @@ test('should restore saved settings', function() {
|
||||
|
||||
test('should not restore saved settings', function() {
|
||||
let player;
|
||||
let newSettings = {
|
||||
backgroundOpacity: '1',
|
||||
textOpacity: '1',
|
||||
windowOpacity: '1',
|
||||
const newSettings = {
|
||||
backgroundOpacity: '0.5',
|
||||
textOpacity: '0.5',
|
||||
windowOpacity: '0.5',
|
||||
edgeStyle: 'raised',
|
||||
fontFamily: 'monospaceSerif',
|
||||
color: '#FFF',
|
||||
color: '#F00',
|
||||
backgroundColor: '#FFF',
|
||||
windowColor: '#FFF',
|
||||
fontPercent: 1.25
|
||||
@ -231,7 +242,7 @@ test('should not restore saved settings', function() {
|
||||
persistTextTrackSettings: false
|
||||
});
|
||||
|
||||
deepEqual(player.textTrackSettings.getValues(), {});
|
||||
deepEqual(player.textTrackSettings.getValues(), defaultSettings);
|
||||
|
||||
player.dispose();
|
||||
});
|
||||
|
@ -339,20 +339,20 @@ test('tracks are parsed once vttjs is loaded', function() {
|
||||
|
||||
test('stops processing if vttjs loading errored out', function() {
|
||||
const clock = sinon.useFakeTimers();
|
||||
const errorSpy = sinon.spy();
|
||||
const oldVTT = window.WebVTT;
|
||||
let parserCreated = false;
|
||||
window.WebVTT = true;
|
||||
|
||||
// use proxyquire to stub xhr module because IE8s XDomainRequest usage
|
||||
let xhrHandler;
|
||||
let errorMsg;
|
||||
let TextTrack = proxyquire('../../../src/js/tracks/text-track.js', {
|
||||
xhr(options, fn) {
|
||||
xhrHandler = fn;
|
||||
},
|
||||
'../utils/log.js': {
|
||||
error(msg) {
|
||||
errorMsg = msg;
|
||||
'default': {
|
||||
error: errorSpy
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -376,8 +376,11 @@ test('stops processing if vttjs loading errored out', function() {
|
||||
testTech.trigger('vttjserror');
|
||||
let offSpyCall = testTech.off.getCall(0);
|
||||
|
||||
ok(/^vttjs failed to load, stopping trying to process/.test(errorMsg),
|
||||
'vttjs failed to load, so, we logged an error');
|
||||
ok(errorSpy.called, 'vttjs failed to load, so log.error was called');
|
||||
if (errorSpy.called) {
|
||||
ok(/^vttjs failed to load, stopping trying to process/.test(errorSpy.getCall(0).args[0]),
|
||||
'log.error was called with the expected message');
|
||||
}
|
||||
ok(!parserCreated, 'WebVTT is not loaded, do not try to parse yet');
|
||||
ok(offSpyCall, 'tech.off was called');
|
||||
|
||||
|
@ -1,56 +1,84 @@
|
||||
import {IE_VERSION} from '../../../src/js/utils/browser';
|
||||
import log from '../../../src/js/utils/log.js';
|
||||
import {logByType} from '../../../src/js/utils/log.js';
|
||||
import window from 'global/window';
|
||||
|
||||
q.module('log');
|
||||
q.module('log', {
|
||||
|
||||
test('should confirm logging functions work', function() {
|
||||
let origConsole = window['console'];
|
||||
// replace the native console for testing
|
||||
// in ie8 console.log is apparently not a 'function' so sinon chokes on it
|
||||
// https://github.com/cjohansen/Sinon.JS/issues/386
|
||||
// instead we'll temporarily replace them with no-op functions
|
||||
let console = window['console'] = {
|
||||
log: function(){},
|
||||
warn: function(){},
|
||||
error: function(){}
|
||||
};
|
||||
beforeEach() {
|
||||
|
||||
// stub the global log functions
|
||||
let logStub = sinon.stub(console, 'log');
|
||||
let errorStub = sinon.stub(console, 'error');
|
||||
let warnStub = sinon.stub(console, 'warn');
|
||||
// Back up the original console.
|
||||
this.originalConsole = window.console;
|
||||
|
||||
// Reset the log history
|
||||
log.history = [];
|
||||
// Replace the native console for testing. In IE8 `console.log` is not a
|
||||
// 'function' so sinon chokes on it when trying to spy:
|
||||
// https://github.com/cjohansen/Sinon.JS/issues/386
|
||||
//
|
||||
// Instead we'll temporarily replace them with no-op functions
|
||||
window.console = {
|
||||
log: sinon.spy(),
|
||||
warn: sinon.spy(),
|
||||
error: sinon.spy()
|
||||
};
|
||||
},
|
||||
|
||||
afterEach() {
|
||||
|
||||
// Restore the native/original console.
|
||||
window.console = this.originalConsole;
|
||||
|
||||
// Empty the logger's history.
|
||||
log.history.length = 0;
|
||||
}
|
||||
});
|
||||
|
||||
const getConsoleArgs = (...arr) =>
|
||||
IE_VERSION && IE_VERSION < 11 ? [arr.join(' ')] : arr;
|
||||
|
||||
test('logging functions should work', function() {
|
||||
|
||||
// Need to reset history here because there are extra messages logged
|
||||
// when running via Karma.
|
||||
log.history.length = 0;
|
||||
|
||||
log('log1', 'log2');
|
||||
log.warn('warn1', 'warn2');
|
||||
log.error('error1', 'error2');
|
||||
|
||||
ok(logStub.called, 'log was called');
|
||||
equal(logStub.firstCall.args[0], 'VIDEOJS:');
|
||||
equal(logStub.firstCall.args[1], 'log1');
|
||||
equal(logStub.firstCall.args[2], 'log2');
|
||||
ok(window.console.log.called, 'log was called');
|
||||
deepEqual(
|
||||
window.console.log.firstCall.args,
|
||||
getConsoleArgs('VIDEOJS:', 'log1', 'log2')
|
||||
);
|
||||
|
||||
ok(warnStub.called, 'warn was called');
|
||||
equal(warnStub.firstCall.args[0], 'VIDEOJS:');
|
||||
equal(warnStub.firstCall.args[1], 'WARN:');
|
||||
equal(warnStub.firstCall.args[2], 'warn1');
|
||||
equal(warnStub.firstCall.args[3], 'warn2');
|
||||
ok(window.console.warn.called, 'warn was called');
|
||||
deepEqual(
|
||||
window.console.warn.firstCall.args,
|
||||
getConsoleArgs('VIDEOJS:', 'WARN:', 'warn1', 'warn2')
|
||||
);
|
||||
|
||||
ok(errorStub.called, 'error was called');
|
||||
equal(errorStub.firstCall.args[0], 'VIDEOJS:');
|
||||
equal(errorStub.firstCall.args[1], 'ERROR:');
|
||||
equal(errorStub.firstCall.args[2], 'error1');
|
||||
equal(errorStub.firstCall.args[3], 'error2');
|
||||
ok(window.console.error.called, 'error was called');
|
||||
deepEqual(
|
||||
window.console.error.firstCall.args,
|
||||
getConsoleArgs('VIDEOJS:', 'ERROR:', 'error1', 'error2')
|
||||
);
|
||||
|
||||
equal(log.history.length, 3, 'there should be three messages in the log history');
|
||||
|
||||
// tear down sinon
|
||||
logStub.restore();
|
||||
errorStub.restore();
|
||||
warnStub.restore();
|
||||
|
||||
// restore the native console
|
||||
window['console'] = origConsole;
|
||||
});
|
||||
|
||||
test('in IE pre-11 (or when requested) objects and arrays are stringified', function() {
|
||||
|
||||
// Run a custom log call, explicitly requesting object/array stringification.
|
||||
logByType('log', [
|
||||
'test',
|
||||
{foo: 'bar'},
|
||||
[1, 2, 3],
|
||||
0,
|
||||
false,
|
||||
null
|
||||
], true);
|
||||
|
||||
ok(window.console.log.called, 'log was called');
|
||||
deepEqual(window.console.log.firstCall.args,
|
||||
['VIDEOJS: test {"foo":"bar"} [1,2,3] 0 false null']);
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user