Comparar commits
48 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| 5f54b95a7a | |||
| b9d811c2e2 | |||
| 876d1128a6 | |||
| 14d36a47ee | |||
| ae788be15f | |||
| 1e1636e1f0 | |||
| 2e46c516f6 | |||
| c306e4f7f3 | |||
| f3f979ae49 | |||
| fc72fb90e7 | |||
| 34a78b8989 | |||
| 8dd01467f3 | |||
| 3e9c53f84f | |||
| b270f58bc8 | |||
| 5b15feb5af | |||
| 4b4954ef4d | |||
| b557695e5a | |||
| 238c752aee | |||
| 58604795f8 | |||
| 20b53206a5 | |||
| ec42a1cfd7 | |||
| 5883c9236e | |||
| 7ae2c885a7 | |||
| c51c19ae88 | |||
| 13d349b0da | |||
| e2bfe09c7b | |||
| e7ca49e668 | |||
| f36da276e3 | |||
| 9f37a64146 | |||
| c51c180b3c | |||
| 68c7ab4748 | |||
| a84623dc9c | |||
| e541af30dc | |||
| a63eb1241d | |||
| 819b787f5f | |||
| b7fdf21a05 | |||
| 11d379cbce | |||
| b9e3e55384 | |||
| 17f856849d | |||
| 06fdbaf73d | |||
| aa2b8e82ff | |||
| cf5d64dd49 | |||
| ed39b68f13 | |||
| b1e7bfd8f8 | |||
| ed3249818e | |||
| 68c4d248d9 | |||
| 6e8ab67a48 | |||
| 7c94ac42cc |
@@ -6,6 +6,48 @@ _(none)_
|
||||
|
||||
--------------------
|
||||
|
||||
## 5.11.2 (2016-08-09)
|
||||
_(none)_
|
||||
|
||||
## 5.11.1 (2016-08-08)
|
||||
* @vxsx fixed legend selector to be more specific. Fixes #3492 ([view](https://github.com/videojs/video.js/pull/3494))
|
||||
|
||||
## 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))
|
||||
* @misteroneill Un-deprecate the videojs.players property ([view](https://github.com/videojs/video.js/pull/3299))
|
||||
* @nickygerritsen Add title to all clickable components ([view](https://github.com/videojs/video.js/pull/3296))
|
||||
* @nickygerritsen Update Dutch language file ([view](https://github.com/videojs/video.js/pull/3297))
|
||||
* @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
|
||||
|
||||
## 5.10.7 (2016-06-27)
|
||||
* @gkatsev pinned node-sass to 3.4 ([view](https://github.com/videojs/video.js/pull/3401))
|
||||
* @mister-ben added try catch to volume and playbackrate checks. Fixes #3315 ([view](https://github.com/videojs/video.js/pull/3320))
|
||||
|
||||
+2
-1
@@ -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
-1
@@ -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.7",
|
||||
"version": "5.11.2",
|
||||
"keywords": [
|
||||
"videojs",
|
||||
"html5",
|
||||
|
||||
externo
+71
-39
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
externo
+1
-1
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
externo
+365
-244
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
externo
+12
-10
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
externo
+1
-1
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
-3
@@ -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>
|
||||
|
||||
externo
BIN
Arquivo binário não exibido.
externo
+3
@@ -94,6 +94,9 @@
|
||||
<glyph glyph-name="audio-description"
|
||||
unicode=""
|
||||
horiz-adv-x="1792" d=" M795.5138904615 457.270933L795.5138904615 1221.5248286325C971.84576475 1225.085121904 1107.39330415 1232.12360523 1207.223857 1161.5835220499998C1303.033991 1093.8857027 1377.7922305 962.20560625 1364.3373135 792.9476205000001C1350.102593 613.9029365000001 1219.6655764999998 463.4600215 1050.12389545 448.2843645000001C965.8259268 440.7398275000001 798.21890505 448.2843645000001 798.21890505 448.2843645000001C798.21890505 448.2843645000001 795.2791410655 453.016494 795.5138904615 457.270933M966.1564647 649.0863960000001C1076.16084135 644.6767075 1152.385591 707.3020429999999 1163.8910079999998 807.9351875C1179.2994744999999 942.71878505 1089.73043585 1030.3691748 960.74508635 1020.7227954L960.74508635 658.08043C960.6196169500002 652.9482330000001 962.7606933 650.3134680000001 966.1564647 649.0863960000001 M1343.2299685 457.3517725000002C1389.9059734 444.3690160000001 1404.0840274999998 496.0596970000001 1424.48294065 532.2791494999999C1469.0084255 611.2788500000001 1502.5101322 712.8584189999999 1503.0416912 828.9881705C1503.8147453000001 995.5680973 1438.8404296 1117.7973688000002 1378.4383305 1200.62456881045L1348.652139905 1200.62456881045C1346.6001063899998 1187.06858424 1356.44474056 1175.024791325 1362.18395859 1164.6588891000001C1408.2649952 1081.49431985 1450.96645015 966.7230041 1451.57490975 834.9817034999999C1452.27106325 683.8655425000002 1402.00636065 557.5072264999999 1343.2299685 457.3517725000002 M1488.0379675 457.3517725000002C1534.7139723999999 444.3690160000001 1548.8825828 496.0671625 1569.29093965 532.2791494999999C1613.8164245 611.2788500000001 1647.3113856500001 712.8584189999999 1647.8496902000002 828.9881705C1648.6227442999998 995.5680973 1583.6484286 1117.7973688000002 1523.2463295 1200.62456881045L1493.460138905 1200.62456881045C1491.40810539 1187.06858424 1501.250041305 1175.021805755 1506.9919575899999 1164.6588891000001C1553.0729942 1081.49431985 1595.7757984 966.7230041 1596.3829087499998 834.9817034999999C1597.07906225 683.8655425000002 1546.8143596500001 557.5072264999999 1488.0379675 457.3517725000002 M1631.9130380000001 457.3517725000002C1678.5890429 444.3690160000001 1692.7576533 496.0671625 1713.1660101500001 532.2791494999999C1757.691495 611.2788500000001 1791.1864561500001 712.8584189999999 1791.7247607000002 828.9881705C1792.4978148 995.5680973 1727.5234991000002 1117.7973688000002 1667.1214 1200.62456881045L1637.3352094050001 1200.62456881045C1635.28317589 1187.06858424 1645.1251118050002 1175.02329854 1650.86702809 1164.6588891000001C1696.9480647 1081.49431985 1739.64951965 966.7230041 1740.25797925 834.9817034999999C1740.95413275 683.8655425000002 1690.6894301500001 557.5072264999999 1631.9130380000001 457.3517725000002 M15.66796875 451.481947L254.03034755 451.481947L319.0356932 551.1747990000001L543.6261075 551.6487970000001C543.6261075 551.6487970000001 543.8541115 483.7032095 543.8541115 451.481947L714.4993835 451.481947L714.4993835 1230.9210795L508.643051 1230.9210795C488.8579955 1197.5411595 15.66796875 451.481947 15.66796875 451.481947L15.66796875 451.481947zM550.0048155000001 959.9708615L550.0048155000001 710.916297L408.4199 711.8642895L550.0048155000001 959.9708615L550.0048155000001 959.9708615z" />
|
||||
<glyph glyph-name="audio"
|
||||
unicode=""
|
||||
horiz-adv-x="1792" d=" M896 1717.3333333333333C524.9066666666668 1717.3333333333333 224 1416.4266666666667 224 1045.3333333333333V522.6666666666665C224 399.0933333333333 324.4266666666667 298.6666666666665 448 298.6666666666665H672V896H373.3333333333334V1045.3333333333333C373.3333333333334 1333.92 607.4133333333334 1568 896 1568S1418.6666666666667 1333.92 1418.6666666666667 1045.3333333333333V896H1120V298.6666666666665H1344C1467.5733333333335 298.6666666666665 1568 399.0933333333333 1568 522.6666666666665V1045.3333333333333C1568 1416.4266666666667 1267.0933333333332 1717.3333333333333 896 1717.3333333333333z" />
|
||||
</font>
|
||||
</defs>
|
||||
</svg>
|
||||
|
||||
|
Antes Largura: | Altura: | Tamanho: 25 KiB Depois Largura: | Altura: | Tamanho: 26 KiB |
externo
BIN
Arquivo binário não exibido.
externo
BIN
Arquivo binário não exibido.
externo
+363
-69
@@ -26,7 +26,7 @@ if (typeof window.HTMLVideoElement === 'undefined') {
|
||||
;
|
||||
|
||||
// UMD (Universal Module Definition)
|
||||
// see https://github.com/umdjs/umd/blob/master/returnExports.js
|
||||
// see https://github.com/umdjs/umd/blob/master/templates/returnExports.js
|
||||
(function (root, factory) {
|
||||
'use strict';
|
||||
|
||||
@@ -72,6 +72,7 @@ var array_push = ArrayPrototype.push;
|
||||
var array_unshift = ArrayPrototype.unshift;
|
||||
var array_concat = ArrayPrototype.concat;
|
||||
var call = FunctionPrototype.call;
|
||||
var apply = FunctionPrototype.apply;
|
||||
var max = Math.max;
|
||||
var min = Math.min;
|
||||
|
||||
@@ -84,19 +85,18 @@ var isRegex; /* inlined from https://npmjs.com/is-regex */ var regexExec = RegEx
|
||||
var isString; /* inlined from https://npmjs.com/is-string */ var strValue = String.prototype.valueOf, tryStringObject = function tryStringObject(value) { try { strValue.call(value); return true; } catch (e) { return false; } }, stringClass = '[object String]'; isString = function isString(value) { if (typeof value === 'string') { return true; } if (typeof value !== 'object') { return false; } return hasToStringTag ? tryStringObject(value) : to_string.call(value) === stringClass; };
|
||||
|
||||
/* inlined from http://npmjs.com/define-properties */
|
||||
var supportsDescriptors = $Object.defineProperty && (function () {
|
||||
try {
|
||||
var obj = {};
|
||||
$Object.defineProperty(obj, 'x', { enumerable: false, value: obj });
|
||||
for (var _ in obj) { return false; }
|
||||
return obj.x === obj;
|
||||
} catch (e) { /* this is ES3 */
|
||||
return false;
|
||||
}
|
||||
}());
|
||||
var defineProperties = (function (has) {
|
||||
var supportsDescriptors = $Object.defineProperty && (function () {
|
||||
try {
|
||||
var obj = {};
|
||||
$Object.defineProperty(obj, 'x', { enumerable: false, value: obj });
|
||||
for (var _ in obj) { return false; }
|
||||
return obj.x === obj;
|
||||
} catch (e) { /* this is ES3 */
|
||||
return false;
|
||||
}
|
||||
}());
|
||||
|
||||
// Define configurable, writable and non-enumerable props
|
||||
// Define configurable, writable, and non-enumerable props
|
||||
// if they don't exist.
|
||||
var defineProperty;
|
||||
if (supportsDescriptors) {
|
||||
@@ -179,7 +179,6 @@ var ES = {
|
||||
// http://es5.github.com/#x9.9
|
||||
/* replaceable with https://npmjs.com/package/es-abstract ES5.ToObject */
|
||||
ToObject: function (o) {
|
||||
/* jshint eqnull: true */
|
||||
if (o == null) { // this matches both null and undefined
|
||||
throw new TypeError("can't convert " + o + ' to object');
|
||||
}
|
||||
@@ -337,13 +336,17 @@ defineProperties(FunctionPrototype, {
|
||||
});
|
||||
|
||||
// _Please note: Shortcuts are defined after `Function.prototype.bind` as we
|
||||
// us it in defining shortcuts.
|
||||
// use it in defining shortcuts.
|
||||
var owns = call.bind(ObjectPrototype.hasOwnProperty);
|
||||
var toStr = call.bind(ObjectPrototype.toString);
|
||||
var arraySlice = call.bind(array_slice);
|
||||
var arraySliceApply = apply.bind(array_slice);
|
||||
var strSlice = call.bind(StringPrototype.slice);
|
||||
var strSplit = call.bind(StringPrototype.split);
|
||||
var strIndexOf = call.bind(StringPrototype.indexOf);
|
||||
var push = call.bind(array_push);
|
||||
var pushCall = call.bind(array_push);
|
||||
var isEnum = call.bind(ObjectPrototype.propertyIsEnumerable);
|
||||
var arraySort = call.bind(ArrayPrototype.sort);
|
||||
|
||||
//
|
||||
// Array
|
||||
@@ -397,18 +400,23 @@ var properlyBoxesContext = function properlyBoxed(method) {
|
||||
// Check node 0.6.21 bug where third parameter is not boxed
|
||||
var properlyBoxesNonStrict = true;
|
||||
var properlyBoxesStrict = true;
|
||||
var threwException = false;
|
||||
if (method) {
|
||||
method.call('foo', function (_, __, context) {
|
||||
if (typeof context !== 'object') { properlyBoxesNonStrict = false; }
|
||||
});
|
||||
try {
|
||||
method.call('foo', function (_, __, context) {
|
||||
if (typeof context !== 'object') { properlyBoxesNonStrict = false; }
|
||||
});
|
||||
|
||||
method.call([1], function () {
|
||||
'use strict';
|
||||
method.call([1], function () {
|
||||
'use strict';
|
||||
|
||||
properlyBoxesStrict = typeof this === 'string';
|
||||
}, 'x');
|
||||
properlyBoxesStrict = typeof this === 'string';
|
||||
}, 'x');
|
||||
} catch (e) {
|
||||
threwException = true;
|
||||
}
|
||||
}
|
||||
return !!method && properlyBoxesNonStrict && properlyBoxesStrict;
|
||||
return !!method && !threwException && properlyBoxesNonStrict && properlyBoxesStrict;
|
||||
};
|
||||
|
||||
defineProperties(ArrayPrototype, {
|
||||
@@ -497,7 +505,7 @@ defineProperties(ArrayPrototype, {
|
||||
if (i in self) {
|
||||
value = self[i];
|
||||
if (typeof T === 'undefined' ? callbackfn(value, i, object) : callbackfn.call(T, value, i, object)) {
|
||||
push(result, value);
|
||||
pushCall(result, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -750,9 +758,9 @@ defineProperties(ArrayPrototype, {
|
||||
var args = arguments;
|
||||
this.length = max(ES.ToInteger(this.length), 0);
|
||||
if (arguments.length > 0 && typeof deleteCount !== 'number') {
|
||||
args = array_slice.call(arguments);
|
||||
args = arraySlice(arguments);
|
||||
if (args.length < 2) {
|
||||
push(args, this.length - start);
|
||||
pushCall(args, this.length - start);
|
||||
} else {
|
||||
args[1] = ES.ToInteger(deleteCount);
|
||||
}
|
||||
@@ -799,7 +807,7 @@ defineProperties(ArrayPrototype, {
|
||||
k += 1;
|
||||
}
|
||||
|
||||
var items = array_slice.call(arguments, 2);
|
||||
var items = arraySlice(arguments, 2);
|
||||
var itemCount = items.length;
|
||||
var to;
|
||||
if (itemCount < actualDeleteCount) {
|
||||
@@ -843,13 +851,31 @@ defineProperties(ArrayPrototype, {
|
||||
}
|
||||
}, !spliceWorksWithLargeSparseArrays || !spliceWorksWithSmallSparseArrays);
|
||||
|
||||
var hasJoinUndefinedBug = [1, 2].join(undefined) !== '1,2';
|
||||
var originalJoin = ArrayPrototype.join;
|
||||
defineProperties(ArrayPrototype, {
|
||||
join: function join(separator) {
|
||||
return originalJoin.call(this, typeof separator === 'undefined' ? ',' : separator);
|
||||
}
|
||||
}, hasJoinUndefinedBug);
|
||||
var hasStringJoinBug;
|
||||
try {
|
||||
hasStringJoinBug = Array.prototype.join.call('123', ',') !== '1,2,3';
|
||||
} catch (e) {
|
||||
hasStringJoinBug = true;
|
||||
}
|
||||
if (hasStringJoinBug) {
|
||||
defineProperties(ArrayPrototype, {
|
||||
join: function join(separator) {
|
||||
var sep = typeof separator === 'undefined' ? ',' : separator;
|
||||
return originalJoin.call(isString(this) ? strSplit(this, '') : this, sep);
|
||||
}
|
||||
}, hasStringJoinBug);
|
||||
}
|
||||
|
||||
var hasJoinUndefinedBug = [1, 2].join(undefined) !== '1,2';
|
||||
if (hasJoinUndefinedBug) {
|
||||
defineProperties(ArrayPrototype, {
|
||||
join: function join(separator) {
|
||||
var sep = typeof separator === 'undefined' ? ',' : separator;
|
||||
return originalJoin.call(this, sep);
|
||||
}
|
||||
}, hasJoinUndefinedBug);
|
||||
}
|
||||
|
||||
var pushShim = function push(item) {
|
||||
var O = ES.ToObject(this);
|
||||
@@ -885,6 +911,52 @@ var pushUndefinedIsWeird = (function () {
|
||||
}());
|
||||
defineProperties(ArrayPrototype, { push: pushShim }, pushUndefinedIsWeird);
|
||||
|
||||
// ES5 15.2.3.14
|
||||
// http://es5.github.io/#x15.4.4.10
|
||||
// Fix boxed string bug
|
||||
defineProperties(ArrayPrototype, {
|
||||
slice: function (start, end) {
|
||||
var arr = isString(this) ? strSplit(this, '') : this;
|
||||
return arraySliceApply(arr, arguments);
|
||||
}
|
||||
}, splitString);
|
||||
|
||||
var sortIgnoresNonFunctions = (function () {
|
||||
try {
|
||||
[1, 2].sort(null);
|
||||
[1, 2].sort({});
|
||||
return true;
|
||||
} catch (e) { /**/ }
|
||||
return false;
|
||||
}());
|
||||
var sortThrowsOnRegex = (function () {
|
||||
// this is a problem in Firefox 4, in which `typeof /a/ === 'function'`
|
||||
try {
|
||||
[1, 2].sort(/a/);
|
||||
return false;
|
||||
} catch (e) { /**/ }
|
||||
return true;
|
||||
}());
|
||||
var sortIgnoresUndefined = (function () {
|
||||
// applies in IE 8, for one.
|
||||
try {
|
||||
[1, 2].sort(undefined);
|
||||
return true;
|
||||
} catch (e) { /**/ }
|
||||
return false;
|
||||
}());
|
||||
defineProperties(ArrayPrototype, {
|
||||
sort: function sort(compareFn) {
|
||||
if (typeof compareFn === 'undefined') {
|
||||
return arraySort(this);
|
||||
}
|
||||
if (!isCallable(compareFn)) {
|
||||
throw new TypeError('Array.prototype.sort callback must be a function');
|
||||
}
|
||||
return arraySort(this, compareFn);
|
||||
}
|
||||
}, sortIgnoresNonFunctions || !sortIgnoresUndefined || !sortThrowsOnRegex);
|
||||
|
||||
//
|
||||
// Object
|
||||
// ======
|
||||
@@ -910,7 +982,8 @@ var blacklistedKeys = {
|
||||
$frames: true,
|
||||
$frameElement: true,
|
||||
$webkitIndexedDB: true,
|
||||
$webkitStorageInfo: true
|
||||
$webkitStorageInfo: true,
|
||||
$external: true
|
||||
};
|
||||
var hasAutomationEqualityBug = (function () {
|
||||
/* globals window */
|
||||
@@ -975,14 +1048,14 @@ defineProperties($Object, {
|
||||
var skipProto = hasProtoEnumBug && isFn;
|
||||
if ((isStr && hasStringEnumBug) || isArgs) {
|
||||
for (var i = 0; i < object.length; ++i) {
|
||||
push(theKeys, $String(i));
|
||||
pushCall(theKeys, $String(i));
|
||||
}
|
||||
}
|
||||
|
||||
if (!isArgs) {
|
||||
for (var name in object) {
|
||||
if (!(skipProto && name === 'prototype') && owns(object, name)) {
|
||||
push(theKeys, $String(name));
|
||||
pushCall(theKeys, $String(name));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -992,7 +1065,7 @@ defineProperties($Object, {
|
||||
for (var j = 0; j < dontEnumsLength; j++) {
|
||||
var dontEnum = dontEnums[j];
|
||||
if (!(skipConstructor && dontEnum === 'constructor') && owns(object, dontEnum)) {
|
||||
push(theKeys, dontEnum);
|
||||
pushCall(theKeys, dontEnum);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1012,7 +1085,7 @@ var originalKeys = $Object.keys;
|
||||
defineProperties($Object, {
|
||||
keys: function keys(object) {
|
||||
if (isArguments(object)) {
|
||||
return originalKeys(array_slice.call(object));
|
||||
return originalKeys(arraySlice(object));
|
||||
} else {
|
||||
return originalKeys(object);
|
||||
}
|
||||
@@ -1024,6 +1097,190 @@ defineProperties($Object, {
|
||||
// ====
|
||||
//
|
||||
|
||||
var hasNegativeMonthYearBug = new Date(-3509827329600292).getUTCMonth() !== 0;
|
||||
var aNegativeTestDate = new Date(-1509842289600292);
|
||||
var aPositiveTestDate = new Date(1449662400000);
|
||||
var hasToUTCStringFormatBug = aNegativeTestDate.toUTCString() !== 'Mon, 01 Jan -45875 11:59:59 GMT';
|
||||
var hasToDateStringFormatBug;
|
||||
var hasToStringFormatBug;
|
||||
var timeZoneOffset = aNegativeTestDate.getTimezoneOffset();
|
||||
if (timeZoneOffset < -720) {
|
||||
hasToDateStringFormatBug = aNegativeTestDate.toDateString() !== 'Tue Jan 02 -45875';
|
||||
hasToStringFormatBug = !(/^Thu Dec 10 2015 \d\d:\d\d:\d\d GMT[-\+]\d\d\d\d(?: |$)/).test(aPositiveTestDate.toString());
|
||||
} else {
|
||||
hasToDateStringFormatBug = aNegativeTestDate.toDateString() !== 'Mon Jan 01 -45875';
|
||||
hasToStringFormatBug = !(/^Wed Dec 09 2015 \d\d:\d\d:\d\d GMT[-\+]\d\d\d\d(?: |$)/).test(aPositiveTestDate.toString());
|
||||
}
|
||||
|
||||
var originalGetFullYear = call.bind(Date.prototype.getFullYear);
|
||||
var originalGetMonth = call.bind(Date.prototype.getMonth);
|
||||
var originalGetDate = call.bind(Date.prototype.getDate);
|
||||
var originalGetUTCFullYear = call.bind(Date.prototype.getUTCFullYear);
|
||||
var originalGetUTCMonth = call.bind(Date.prototype.getUTCMonth);
|
||||
var originalGetUTCDate = call.bind(Date.prototype.getUTCDate);
|
||||
var originalGetUTCDay = call.bind(Date.prototype.getUTCDay);
|
||||
var originalGetUTCHours = call.bind(Date.prototype.getUTCHours);
|
||||
var originalGetUTCMinutes = call.bind(Date.prototype.getUTCMinutes);
|
||||
var originalGetUTCSeconds = call.bind(Date.prototype.getUTCSeconds);
|
||||
var originalGetUTCMilliseconds = call.bind(Date.prototype.getUTCMilliseconds);
|
||||
var dayName = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri'];
|
||||
var monthName = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
||||
var daysInMonth = function daysInMonth(month, year) {
|
||||
return originalGetDate(new Date(year, month, 0));
|
||||
};
|
||||
|
||||
defineProperties(Date.prototype, {
|
||||
getFullYear: function getFullYear() {
|
||||
if (!this || !(this instanceof Date)) {
|
||||
throw new TypeError('this is not a Date object.');
|
||||
}
|
||||
var year = originalGetFullYear(this);
|
||||
if (year < 0 && originalGetMonth(this) > 11) {
|
||||
return year + 1;
|
||||
}
|
||||
return year;
|
||||
},
|
||||
getMonth: function getMonth() {
|
||||
if (!this || !(this instanceof Date)) {
|
||||
throw new TypeError('this is not a Date object.');
|
||||
}
|
||||
var year = originalGetFullYear(this);
|
||||
var month = originalGetMonth(this);
|
||||
if (year < 0 && month > 11) {
|
||||
return 0;
|
||||
}
|
||||
return month;
|
||||
},
|
||||
getDate: function getDate() {
|
||||
if (!this || !(this instanceof Date)) {
|
||||
throw new TypeError('this is not a Date object.');
|
||||
}
|
||||
var year = originalGetFullYear(this);
|
||||
var month = originalGetMonth(this);
|
||||
var date = originalGetDate(this);
|
||||
if (year < 0 && month > 11) {
|
||||
if (month === 12) {
|
||||
return date;
|
||||
}
|
||||
var days = daysInMonth(0, year + 1);
|
||||
return (days - date) + 1;
|
||||
}
|
||||
return date;
|
||||
},
|
||||
getUTCFullYear: function getUTCFullYear() {
|
||||
if (!this || !(this instanceof Date)) {
|
||||
throw new TypeError('this is not a Date object.');
|
||||
}
|
||||
var year = originalGetUTCFullYear(this);
|
||||
if (year < 0 && originalGetUTCMonth(this) > 11) {
|
||||
return year + 1;
|
||||
}
|
||||
return year;
|
||||
},
|
||||
getUTCMonth: function getUTCMonth() {
|
||||
if (!this || !(this instanceof Date)) {
|
||||
throw new TypeError('this is not a Date object.');
|
||||
}
|
||||
var year = originalGetUTCFullYear(this);
|
||||
var month = originalGetUTCMonth(this);
|
||||
if (year < 0 && month > 11) {
|
||||
return 0;
|
||||
}
|
||||
return month;
|
||||
},
|
||||
getUTCDate: function getUTCDate() {
|
||||
if (!this || !(this instanceof Date)) {
|
||||
throw new TypeError('this is not a Date object.');
|
||||
}
|
||||
var year = originalGetUTCFullYear(this);
|
||||
var month = originalGetUTCMonth(this);
|
||||
var date = originalGetUTCDate(this);
|
||||
if (year < 0 && month > 11) {
|
||||
if (month === 12) {
|
||||
return date;
|
||||
}
|
||||
var days = daysInMonth(0, year + 1);
|
||||
return (days - date) + 1;
|
||||
}
|
||||
return date;
|
||||
}
|
||||
}, hasNegativeMonthYearBug);
|
||||
|
||||
defineProperties(Date.prototype, {
|
||||
toUTCString: function toUTCString() {
|
||||
if (!this || !(this instanceof Date)) {
|
||||
throw new TypeError('this is not a Date object.');
|
||||
}
|
||||
var day = originalGetUTCDay(this);
|
||||
var date = originalGetUTCDate(this);
|
||||
var month = originalGetUTCMonth(this);
|
||||
var year = originalGetUTCFullYear(this);
|
||||
var hour = originalGetUTCHours(this);
|
||||
var minute = originalGetUTCMinutes(this);
|
||||
var second = originalGetUTCSeconds(this);
|
||||
return dayName[day] + ', ' +
|
||||
(date < 10 ? '0' + date : date) + ' ' +
|
||||
monthName[month] + ' ' +
|
||||
year + ' ' +
|
||||
(hour < 10 ? '0' + hour : hour) + ':' +
|
||||
(minute < 10 ? '0' + minute : minute) + ':' +
|
||||
(second < 10 ? '0' + second : second) + ' GMT';
|
||||
}
|
||||
}, hasNegativeMonthYearBug || hasToUTCStringFormatBug);
|
||||
|
||||
// Opera 12 has `,`
|
||||
defineProperties(Date.prototype, {
|
||||
toDateString: function toDateString() {
|
||||
if (!this || !(this instanceof Date)) {
|
||||
throw new TypeError('this is not a Date object.');
|
||||
}
|
||||
var day = this.getDay();
|
||||
var date = this.getDate();
|
||||
var month = this.getMonth();
|
||||
var year = this.getFullYear();
|
||||
return dayName[day] + ' ' +
|
||||
monthName[month] + ' ' +
|
||||
(date < 10 ? '0' + date : date) + ' ' +
|
||||
year;
|
||||
}
|
||||
}, hasNegativeMonthYearBug || hasToDateStringFormatBug);
|
||||
|
||||
// can't use defineProperties here because of toString enumeration issue in IE <= 8
|
||||
if (hasNegativeMonthYearBug || hasToStringFormatBug) {
|
||||
Date.prototype.toString = function toString() {
|
||||
if (!this || !(this instanceof Date)) {
|
||||
throw new TypeError('this is not a Date object.');
|
||||
}
|
||||
var day = this.getDay();
|
||||
var date = this.getDate();
|
||||
var month = this.getMonth();
|
||||
var year = this.getFullYear();
|
||||
var hour = this.getHours();
|
||||
var minute = this.getMinutes();
|
||||
var second = this.getSeconds();
|
||||
var timezoneOffset = this.getTimezoneOffset();
|
||||
var hoursOffset = Math.floor(Math.abs(timezoneOffset) / 60);
|
||||
var minutesOffset = Math.floor(Math.abs(timezoneOffset) % 60);
|
||||
return dayName[day] + ' ' +
|
||||
monthName[month] + ' ' +
|
||||
(date < 10 ? '0' + date : date) + ' ' +
|
||||
year + ' ' +
|
||||
(hour < 10 ? '0' + hour : hour) + ':' +
|
||||
(minute < 10 ? '0' + minute : minute) + ':' +
|
||||
(second < 10 ? '0' + second : second) + ' GMT' +
|
||||
(timezoneOffset > 0 ? '-' : '+') +
|
||||
(hoursOffset < 10 ? '0' + hoursOffset : hoursOffset) +
|
||||
(minutesOffset < 10 ? '0' + minutesOffset : minutesOffset);
|
||||
};
|
||||
if (supportsDescriptors) {
|
||||
$Object.defineProperty(Date.prototype, 'toString', {
|
||||
configurable: true,
|
||||
enumerable: false,
|
||||
writable: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ES5 15.9.5.43
|
||||
// http://es5.github.com/#x15.9.5.43
|
||||
// This function returns a String value represent the instance in time
|
||||
@@ -1038,39 +1295,33 @@ var hasSafari51DateBug = Date.prototype.toISOString && new Date(-1).toISOString(
|
||||
|
||||
defineProperties(Date.prototype, {
|
||||
toISOString: function toISOString() {
|
||||
var result, length, value, year, month;
|
||||
if (!isFinite(this)) {
|
||||
throw new RangeError('Date.prototype.toISOString called on non-finite value.');
|
||||
}
|
||||
|
||||
year = this.getUTCFullYear();
|
||||
var year = originalGetUTCFullYear(this);
|
||||
|
||||
month = this.getUTCMonth();
|
||||
var month = originalGetUTCMonth(this);
|
||||
// see https://github.com/es-shims/es5-shim/issues/111
|
||||
year += Math.floor(month / 12);
|
||||
month = (month % 12 + 12) % 12;
|
||||
|
||||
// the date time string format is specified in 15.9.1.15.
|
||||
result = [month + 1, this.getUTCDate(), this.getUTCHours(), this.getUTCMinutes(), this.getUTCSeconds()];
|
||||
var result = [month + 1, originalGetUTCDate(this), originalGetUTCHours(this), originalGetUTCMinutes(this), originalGetUTCSeconds(this)];
|
||||
year = (
|
||||
(year < 0 ? '-' : (year > 9999 ? '+' : '')) +
|
||||
strSlice('00000' + Math.abs(year), (0 <= year && year <= 9999) ? -4 : -6)
|
||||
);
|
||||
|
||||
length = result.length;
|
||||
while (length--) {
|
||||
value = result[length];
|
||||
// pad months, days, hours, minutes, and seconds to have two
|
||||
// digits.
|
||||
if (value < 10) {
|
||||
result[length] = '0' + value;
|
||||
}
|
||||
for (var i = 0; i < result.length; ++i) {
|
||||
// pad months, days, hours, minutes, and seconds to have two digits.
|
||||
result[i] = strSlice('00' + result[i], -2);
|
||||
}
|
||||
// pad milliseconds to have three digits.
|
||||
return (
|
||||
year + '-' + array_slice.call(result, 0, 2).join('-') +
|
||||
'T' + array_slice.call(result, 2).join(':') + '.' +
|
||||
strSlice('000' + this.getUTCMilliseconds(), -3) + 'Z'
|
||||
year + '-' + arraySlice(result, 0, 2).join('-') +
|
||||
'T' + arraySlice(result, 2).join(':') + '.' +
|
||||
strSlice('000' + originalGetUTCMilliseconds(this), -3) + 'Z'
|
||||
);
|
||||
}
|
||||
}, hasNegativeDateBug || hasSafari51DateBug);
|
||||
@@ -1140,7 +1391,6 @@ if (doesNotParseY2KNewYear || acceptsInvalidDates || !supportsExtendedYears) {
|
||||
/* global Date: true */
|
||||
/* eslint-disable no-undef */
|
||||
var maxSafeUnsigned32Bit = Math.pow(2, 31) - 1;
|
||||
var secondsWithinMaxSafeUnsigned32Bit = Math.floor(maxSafeUnsigned32Bit / 1e3);
|
||||
var hasSafariSignedIntBug = isActualNaN(new Date(1970, 0, 1, 0, 0, 0, maxSafeUnsigned32Bit + 1).getTime());
|
||||
Date = (function (NativeDate) {
|
||||
/* eslint-enable no-undef */
|
||||
@@ -1513,7 +1763,7 @@ if (
|
||||
var maxSafe32BitInt = Math.pow(2, 32) - 1;
|
||||
|
||||
StringPrototype.split = function (separator, limit) {
|
||||
var string = this;
|
||||
var string = String(this);
|
||||
if (typeof separator === 'undefined' && limit === 0) {
|
||||
return [];
|
||||
}
|
||||
@@ -1532,7 +1782,6 @@ if (
|
||||
// Make `global` and avoid `lastIndex` issues by working with a copy
|
||||
separator2, match, lastIndex, lastLength;
|
||||
var separatorCopy = new RegExp(separator.source, flags + 'g');
|
||||
string += ''; // Type-convert
|
||||
if (!compliantExecNpcg) {
|
||||
// Doesn't need flags gy, but they don't hurt
|
||||
separator2 = new RegExp('^' + separatorCopy.source + '$(?!\\s)', flags);
|
||||
@@ -1550,7 +1799,7 @@ if (
|
||||
// `separatorCopy.lastIndex` is not reliable cross-browser
|
||||
lastIndex = match.index + match[0].length;
|
||||
if (lastIndex > lastLastIndex) {
|
||||
push(output, strSlice(string, lastLastIndex, match.index));
|
||||
pushCall(output, strSlice(string, lastLastIndex, match.index));
|
||||
// Fix browsers whose `exec` methods don't consistently return `undefined` for
|
||||
// nonparticipating capturing groups
|
||||
if (!compliantExecNpcg && match.length > 1) {
|
||||
@@ -1565,7 +1814,7 @@ if (
|
||||
/* eslint-enable no-loop-func */
|
||||
}
|
||||
if (match.length > 1 && match.index < string.length) {
|
||||
array_push.apply(output, array_slice.call(match, 1));
|
||||
array_push.apply(output, arraySlice(match, 1));
|
||||
}
|
||||
lastLength = match[0].length;
|
||||
lastLastIndex = lastIndex;
|
||||
@@ -1580,10 +1829,10 @@ if (
|
||||
}
|
||||
if (lastLastIndex === string.length) {
|
||||
if (lastLength || !separatorCopy.test('')) {
|
||||
push(output, '');
|
||||
pushCall(output, '');
|
||||
}
|
||||
} else {
|
||||
push(output, strSlice(string, lastLastIndex));
|
||||
pushCall(output, strSlice(string, lastLastIndex));
|
||||
}
|
||||
return output.length > splitLimit ? strSlice(output, 0, splitLimit) : output;
|
||||
};
|
||||
@@ -1606,7 +1855,7 @@ var str_replace = StringPrototype.replace;
|
||||
var replaceReportsGroupsCorrectly = (function () {
|
||||
var groups = [];
|
||||
'x'.replace(/x(.)?/g, function (match, group) {
|
||||
push(groups, group);
|
||||
pushCall(groups, group);
|
||||
});
|
||||
return groups.length === 1 && typeof groups[0] === 'undefined';
|
||||
}());
|
||||
@@ -1624,7 +1873,7 @@ if (!replaceReportsGroupsCorrectly) {
|
||||
searchValue.lastIndex = 0;
|
||||
var args = searchValue.exec(match) || [];
|
||||
searchValue.lastIndex = originalLastIndex;
|
||||
push(args, arguments[length - 2], arguments[length - 1]);
|
||||
pushCall(args, arguments[length - 2], arguments[length - 1]);
|
||||
return replaceValue.apply(this, args);
|
||||
};
|
||||
return str_replace.call(this, searchValue, wrappedReplaceValue);
|
||||
@@ -1669,6 +1918,7 @@ defineProperties(StringPrototype, {
|
||||
return $String(this).replace(trimBeginRegexp, '').replace(trimEndRegexp, '');
|
||||
}
|
||||
}, hasTrimWhitespaceBug);
|
||||
var trim = call.bind(String.prototype.trim);
|
||||
|
||||
var hasLastIndexBug = StringPrototype.lastIndexOf && 'abcあい'.lastIndexOf('あい', 2) !== -1;
|
||||
defineProperties(StringPrototype, {
|
||||
@@ -1709,15 +1959,26 @@ if (parseInt(ws + '08') !== 8 || parseInt(ws + '0x16') !== 22) {
|
||||
parseInt = (function (origParseInt) {
|
||||
var hexRegex = /^[\-+]?0[xX]/;
|
||||
return function parseInt(str, radix) {
|
||||
var string = $String(str).trim();
|
||||
var string = trim(str);
|
||||
var defaultedRadix = $Number(radix) || (hexRegex.test(string) ? 16 : 10);
|
||||
return origParseInt(string, defaultedRadix);
|
||||
};
|
||||
}(parseInt));
|
||||
}
|
||||
|
||||
// https://es5.github.io/#x15.1.2.3
|
||||
if (1 / parseFloat('-0') !== -Infinity) {
|
||||
/* global parseFloat: true */
|
||||
parseFloat = (function (origParseFloat) {
|
||||
return function parseFloat(string) {
|
||||
var inputString = trim(string);
|
||||
var result = origParseFloat(inputString);
|
||||
return result === 0 && strSlice(inputString, 0, 1) === '-' ? -0 : result;
|
||||
};
|
||||
}(parseFloat));
|
||||
}
|
||||
|
||||
if (String(new RangeError('test')) !== 'RangeError: test') {
|
||||
var originalErrorToString = Error.prototype.toString;
|
||||
var errorToStringShim = function toString() {
|
||||
if (typeof this === 'undefined' || this === null) {
|
||||
throw new TypeError("can't convert " + this + ' to object');
|
||||
@@ -1746,6 +2007,39 @@ if (String(new RangeError('test')) !== 'RangeError: test') {
|
||||
Error.prototype.toString = errorToStringShim;
|
||||
}
|
||||
|
||||
if (supportsDescriptors) {
|
||||
var ensureNonEnumerable = function (obj, prop) {
|
||||
if (isEnum(obj, prop)) {
|
||||
var desc = Object.getOwnPropertyDescriptor(obj, prop);
|
||||
desc.enumerable = false;
|
||||
Object.defineProperty(obj, prop, desc);
|
||||
}
|
||||
};
|
||||
ensureNonEnumerable(Error.prototype, 'message');
|
||||
if (Error.prototype.message !== '') {
|
||||
Error.prototype.message = '';
|
||||
}
|
||||
ensureNonEnumerable(Error.prototype, 'name');
|
||||
}
|
||||
|
||||
if (String(/a/mig) !== '/a/gim') {
|
||||
var regexToString = function toString() {
|
||||
var str = '/' + this.source + '/';
|
||||
if (this.global) {
|
||||
str += 'g';
|
||||
}
|
||||
if (this.ignoreCase) {
|
||||
str += 'i';
|
||||
}
|
||||
if (this.multiline) {
|
||||
str += 'm';
|
||||
}
|
||||
return str;
|
||||
};
|
||||
// can't use defineProperties here because of toString enumeration issue in IE <= 8
|
||||
RegExp.prototype.toString = regexToString;
|
||||
}
|
||||
|
||||
}));
|
||||
|
||||
/*!
|
||||
@@ -1760,7 +2054,7 @@ if (String(new RangeError('test')) !== 'RangeError: test') {
|
||||
;
|
||||
|
||||
// UMD (Universal Module Definition)
|
||||
// see https://github.com/umdjs/umd/blob/master/returnExports.js
|
||||
// see https://github.com/umdjs/umd/blob/master/templates/returnExports.js
|
||||
(function (root, factory) {
|
||||
'use strict';
|
||||
|
||||
@@ -1779,10 +2073,10 @@ if (String(new RangeError('test')) !== 'RangeError: test') {
|
||||
}
|
||||
}(this, function () {
|
||||
|
||||
var call = Function.prototype.call;
|
||||
var call = Function.call;
|
||||
var prototypeOfObject = Object.prototype;
|
||||
var owns = call.bind(prototypeOfObject.hasOwnProperty);
|
||||
var propertyIsEnumerable = call.bind(prototypeOfObject.propertyIsEnumerable);
|
||||
var isEnumerable = call.bind(prototypeOfObject.propertyIsEnumerable);
|
||||
var toStr = call.bind(prototypeOfObject.toString);
|
||||
|
||||
// If JS engine supports accessors creating shortcuts.
|
||||
@@ -1881,7 +2175,7 @@ if (!Object.getOwnPropertyDescriptor || getOwnPropertyDescriptorFallback) {
|
||||
// If object has a property then it's for sure `configurable`, and
|
||||
// probably `enumerable`. Detect enumerability though.
|
||||
descriptor = {
|
||||
enumerable: propertyIsEnumerable(object, property),
|
||||
enumerable: isEnumerable(object, property),
|
||||
configurable: true
|
||||
};
|
||||
|
||||
|
||||
externo
+1
-1
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
externo
+1
@@ -18,6 +18,7 @@ videojs.addLanguage("en",{
|
||||
"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",
|
||||
|
||||
externo
+15
-4
@@ -14,13 +14,24 @@ videojs.addLanguage("nl",{
|
||||
"Unmute": "Geluid aan",
|
||||
"Playback Rate": "Weergavesnelheid",
|
||||
"Subtitles": "Ondertiteling",
|
||||
"subtitles off": "Ondertiteling uit",
|
||||
"Captions": "Ondertiteling",
|
||||
"captions off": "Ondertiteling uit",
|
||||
"subtitles off": "ondertiteling uit",
|
||||
"Captions": "Bijschriften",
|
||||
"captions off": "bijschriften uit",
|
||||
"Chapters": "Hoofdstukken",
|
||||
"Descriptions": "Beschrijvingen",
|
||||
"descriptions off": "beschrijvingen off",
|
||||
"You aborted the media playback": "U hebt de mediaweergave afgebroken.",
|
||||
"A network error caused the media download to fail part-way.": "De mediadownload is mislukt door een netwerkfout.",
|
||||
"The media could not be loaded, either because the server or network failed or because the format is not supported.": "De media kon niet worden geladen, vanwege een server- of netwerkfout of doordat het formaat niet wordt ondersteund.",
|
||||
"The media playback was aborted due to a corruption problem or because the media used features your browser did not support.": "De mediaweergave is afgebroken vanwege beschadigde data of het mediabestand gebruikt functies die niet door uw browser worden ondersteund.",
|
||||
"No compatible source was found for this media.": "Voor deze media is geen ondersteunde bron gevonden."
|
||||
"No compatible source was found for this media.": "Voor deze media is geen ondersteunde bron gevonden.",
|
||||
"Play Video": "Video Afspelen",
|
||||
"Close": "Sluiten",
|
||||
"Modal Window": "Modal Venster",
|
||||
"This is a modal window": "Dit is een modaal venster",
|
||||
"This modal can be closed by pressing the Escape key or activating the close button.": "Dit modaal venster kan gesloten worden door op Escape te drukken of de 'sluiten' knop te activeren.",
|
||||
", opens captions settings dialog": ", opent bijschriften instellingen venster",
|
||||
", opens subtitles settings dialog": ", opent ondertiteling instellingen venster",
|
||||
", opens descriptions settings dialog": ", opent beschrijvingen instellingen venster",
|
||||
", selected": ", selected"
|
||||
});
|
||||
Arquivo binário não exibido.
externo
+71
-39
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
externo
+1
-1
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
externo
+365
-244
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
externo
+16
-18
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
externo
+12
-10
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
externo
+1
-1
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
@@ -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>
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
# Audio Tracks
|
||||
|
||||
Audio Tracks are a function of HTML5 video for providing alternative audio track selections to the user, so that a track other than the main track can be played. Video.js makes audio tracks work across all browsers. There are currently five types of tracks:
|
||||
|
||||
- **Alternative**: alternative audio for the main video track
|
||||
- **Descriptions**: descriptions of what is happening in the video track
|
||||
- **Main**: the main audio track for this video
|
||||
- **Translation**: a translation of the main audio track
|
||||
- **Commentary**: commentary on the video, usually the director of the content talking about design choices
|
||||
|
||||
## Missing Funtionality
|
||||
- It is currently impossible to add AudioTracks in a non-programtic way
|
||||
- Literal switching of AudioTracks for playback is not handled by video.js and must be handled by something else. video.js only stores the track representation
|
||||
|
||||
## Adding to Video.js
|
||||
|
||||
> Right now adding audio tracks in the HTML is unsupported. Audio Tracks must be added programatically.
|
||||
|
||||
You must add audio tracks [programatically](#api) for the time being.
|
||||
|
||||
## Attributes
|
||||
Audio Track propertites and settings
|
||||
|
||||
### kind
|
||||
One of the five track types listed above. Kind defaults to empty string if no kind is included, or an invalid kind is used.
|
||||
|
||||
### label
|
||||
The label for the track that will be show to the user, for example in a menu that list the different languages available for audio tracks.
|
||||
|
||||
### language
|
||||
The two-letter code (valid BCP 47 language tag) for the language of the audio track, for example "en" for English. A list of language codes is [available here](languages.md#language-codes).
|
||||
|
||||
### enabled
|
||||
If this track should be playing or not. In video.js we only allow one track to be enabled at a time. so if you enable more than one the last one to be enabled will end up being the only one.
|
||||
|
||||
## Interacting with Audio Tracks
|
||||
### Doing something when a track becomes enabled
|
||||
When a new track is enabled (other than the main track) an event is fired on the `AudioTrackList` called `change` you can listen to that event and do something with it.
|
||||
Here's an example:
|
||||
```js
|
||||
// get the current players AudioTrackList object
|
||||
let tracks = player.audioTracks();
|
||||
|
||||
// listen to the change event
|
||||
tracks.addEventListener('change', function() {
|
||||
|
||||
// print the currently enabled AudioTrack label
|
||||
for (let i = 0; i < tracks.length; i++) {
|
||||
let track = tracks[i];
|
||||
|
||||
if (track.enabled) {
|
||||
console.log(track.label);
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### `player.audioTracks() -> AudioTrackList`
|
||||
This is the main interface into the audio tracks of the player.
|
||||
It returns an AudioTrackList which is an array like object that contains all the `AudioTrack` on the player.
|
||||
|
||||
### `player.audioTracks().addTrack(AudioTrack)`
|
||||
Add an existing AudioTrack to the players internal list of AudioTracks.
|
||||
|
||||
### `player.audioTracks().removeTrack(AudioTrack)`
|
||||
Remove a track from the AudioTrackList currently on the player. if no track exists this will do nothing.
|
||||
@@ -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
|
||||
------------------
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
# Text Tracks
|
||||
|
||||
Text Tracks are a function of HTML5 video for providing time triggered text to the viewer. Video.js makes tracks work across all browsers. There are currently five types of tracks:
|
||||
|
||||
- **Subtitles**: Translations of the dialogue in the video for when audio is available but not understood. Subtitles are shown over the video.
|
||||
- **Captions**: Transcription of the dialogue, sound effects, musical cues, and other audio information for when the viewer is deaf/hard of hearing, or the video is muted. Captions are also shown over the video.
|
||||
- **Chapters**: Chapter titles that are used to create navigation within the video. Typically they're in the form of a list of chapters that the viewer can click on to go to a specific chapter.
|
||||
- **Descriptions**: Text descriptions of what's happening in the video for when the video portion isn't available, because the viewer is blind, not using a screen, or driving and about to crash because they're trying to enjoy a video while driving. Descriptions are read by a screen reader or turned into a separate audio track.
|
||||
- **Metadata**: Tracks that have data meant for javascript to parse and do something with. These aren't shown to the user.
|
||||
|
||||
## Creating the Text File
|
||||
Timed text requires a text file in [WebVTT](http://dev.w3.org/html5/webvtt/) format. This format defines a list of "cues" that have a start time, and end time, and text to display. [Microsoft has a builder](https://dev.modern.ie/testdrive/demos/captionmaker/) that can help you get started on the file.
|
||||
|
||||
When creating captions, there's also additional [caption formatting techniques] (http://www.theneitherworld.com/mcpoodle/SCC_TOOLS/DOCS/SCC_FORMAT.HTML#style) that would be good to use, like brackets around sound effects: [ sound effect ]. If you'd like a more in depth style guide for captioning, you can reference the [Captioning Key](http://www.dcmp.org/captioningkey/), but keep in mind not all features are supported by WebVTT or (more likely) the Video.js WebVTT implementation.
|
||||
|
||||
## Adding to Video.js
|
||||
Once you have your WebVTT file created, you can add it to Video.js using the track tag. Put your track tag after all the source elements, and before any fallback content.
|
||||
|
||||
```html
|
||||
<video id="example_video_1" class="video-js"
|
||||
controls preload="auto" width="640" height="264"
|
||||
data-setup='{"example_option":true}'>
|
||||
<source src="http://vjs.zencdn.net/v/oceans.mp4" type="video/mp4" />
|
||||
<source src="http://vjs.zencdn.net/v/oceans.webm" type="video/webm" />
|
||||
<source src="http://vjs.zencdn.net/v/oceans.ogv" type="video/ogg" />
|
||||
|
||||
<track kind="captions" src="http://example.com/path/to/captions.vtt" srclang="en" label="English" default>
|
||||
|
||||
</video>
|
||||
```
|
||||
|
||||
You can also add tracks [programatically](#api).
|
||||
|
||||
## Subtitles from Another Domain
|
||||
Because we're pulling in the text track file via Javascript, the [same-origin policy](http://en.wikipedia.org/wiki/Same_origin_policy) applies. If you'd like to have a player served from one domain,
|
||||
but the text track served from another, you'll need to [enable CORS](http://enable-cors.org/) in order to do so.
|
||||
In addition to enabling CORS on the server serving the text tracks, you will need to add the [`crossorigin` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes) to the video element itself. This attribute has two values `anonymous` and `use-credentials`. Most users will want to use `anonymous` with cross-origin tracks.
|
||||
It can be added to the video element like so:
|
||||
```html
|
||||
<video class="video-js" crossorigin="anonymous">
|
||||
<source src="http://vjs.zencdn.net/v/oceans.mp4" type="video/mp4">
|
||||
<track src="http://example.com/oceans.vtt" kind="captions" srclang="en" label="English">
|
||||
</video>
|
||||
```
|
||||
One thing to be aware of is that in this case the video files themselves will *also* needs CORS headers applied to it. This is because some browsers apply the crossorigin attribute to the video source itself and not just the tracks and is considered a [security concern by the spec](https://html.spec.whatwg.org/multipage/embedded-content.html#security-and-privacy-considerations).
|
||||
|
||||
## Track Attributes
|
||||
Additional settings for track tags.
|
||||
|
||||
### kind
|
||||
One of the five track types listed above. Kind defaults to subtitles if no kind is included.
|
||||
|
||||
### label
|
||||
The label for the track that will be show to the user, for example in a menu that list the different languages available for subtitles.
|
||||
|
||||
### default
|
||||
The default attribute can be used to have a track default to showing. Otherwise the viewer would need to select their language from the captions or subtitles menu.
|
||||
NOTE: For chapters, default is required if you want the chapters menu to show.
|
||||
|
||||
### srclang
|
||||
The two-letter code (valid BCP 47 language tag) for the language of the text track, for example "en" for English. A list of language codes is [available here](languages.md#language-codes).
|
||||
|
||||
## Interacting with Text Tracks
|
||||
### Showing tracks programmatically
|
||||
Some of you would want to turn captions on and off programmatically rather than just forcing the user to do so themselves. This can be easily achieved by modifying the `mode` of the text tracks.
|
||||
The `mode` can be one of three values `disabled`, `hidden`, and `showing`.
|
||||
When a text track's `mode` is `disabled`, the track does not show on screen as the video is playing.
|
||||
When the `mode` is set to `showing`, the track is visible to the viewer and updates while the video is playing.
|
||||
You can change of a particular track like so:
|
||||
```js
|
||||
let tracks = player.textTracks();
|
||||
|
||||
for (let i = 0; i < tracks.length; i++) {
|
||||
let track = tracks[i];
|
||||
|
||||
// find the captions track that's in english
|
||||
if (track.kind === 'captions' && track.language === 'en') {
|
||||
track.mode = 'showing';
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Doing something when a cue becomes active
|
||||
Above, we mentioned that `mode` can also be `hidden`, what this means is that the track will update
|
||||
as the video is playing but it won't be visible to the viewer. This is most useful for `metadata` text tracks.
|
||||
One usecase for metadata text tracks is to have something happen when their cues become active, to do so, you listen to the `cuechange` event on the track. These events fire when the mode is `showing` as well.
|
||||
Here's an example:
|
||||
```js
|
||||
let tracks = player.textTracks();
|
||||
let metadataTrack;
|
||||
|
||||
for (let i = 0; i < tracks.length; i++) {
|
||||
let track = tracks[i];
|
||||
|
||||
// find the metadata track that's labeled ads
|
||||
if (track.kind === 'captions' && track.label === 'ads') {
|
||||
track.mode = 'hidden';
|
||||
// store it for usage outside of the loop
|
||||
metadataTrack = track;
|
||||
}
|
||||
}
|
||||
|
||||
metadataTrack.addEventListener('cuechange', function() {
|
||||
player.ads.startLinearAdMode();
|
||||
});
|
||||
```
|
||||
|
||||
## Emulated Text Tracks
|
||||
By default, video.js will try and use native text tracks if possible and fall back to emulated text tracks if the native functionality is broken or incomplete or non-existent.
|
||||
The Flash tech will always use the emulated text track functionality.
|
||||
The video.js API and TextTrack objects were modeled after the w3c's specification.
|
||||
video.js uses [Mozilla's vtt.js](https://github.com/mozilla/vtt.js) library to parse and display its emulated text tracks.
|
||||
|
||||
If you wanted to disable native text track functionality and force video.js to use emulated text tracks always, you can supply the `nativeTextTracks` option to the tech like so:
|
||||
```js
|
||||
let player = videojs('myvideo', {
|
||||
html5: {
|
||||
nativeTextTracks: false
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Text Track Settings
|
||||
When using emulated Text Tracks, captions will have an additional item in the menu called "caption settings".
|
||||
This allows the viewer of the player to change some styles of how the captions are displayed on screen.
|
||||
|
||||
If you don't want that, you can disable it by turning off the text track settings component and hiding the menu item like so:
|
||||
```js
|
||||
let player = videojs('myvideo', {
|
||||
// make the text track settings dialog not initialize
|
||||
textTrackSettings: false
|
||||
});
|
||||
```
|
||||
```css
|
||||
/* hide the captions settings item from the captions menu */
|
||||
.vjs-texttrack-settings {
|
||||
display: none;
|
||||
}
|
||||
```
|
||||
|
||||
## Text Track Precedence
|
||||
In general, the Descriptions tracks is of lower precedence than captions and subtitles.
|
||||
What this means for you?
|
||||
* If you are using the `default` attribute, videojs will choose the first track that is marked as `default` and turn it on. If There are multiple tracks marked `default`, it will try and turn on the first `captions` or `subtitles` track *before* any `descriptions` tracks.
|
||||
* This only applied to the emulated captions support, native text tracks behavior will change depending on the browser
|
||||
* If you select a given track from the menu, videojs will turn off all the other tracks of the same kind. This may seem like you can have both subtitles and captions turned on at the same time but unfortuantely, at this time we only support one track being displayed at a time.
|
||||
* This means that for emulated text tracks, we'll choose the first captions or subtitles track that is enabled to display.
|
||||
* When native text tracks are supported, we will still disable the other tracks of the same kind but it is possible that multiple text tracks are shown.
|
||||
* If a `descriptions` track is selected and subsequently a `subtitles` or `captions` track is selected, the `descriptions` track is disabled and its menu button is also disabled.
|
||||
* When enabling a track programmatically, there's not much checking that videojs does.
|
||||
* For emulated text tracks, when it's time to display the captions, video.js would choose the first track that's showing, again choosing `subtitles` or `captions` over `descriptions`, if necessary.
|
||||
* For native text tracks, this behavior depends on the browser. Some browsers will let you have multiple text tracks but others will disable all other tracks when a new one is selected.
|
||||
|
||||
## API
|
||||
|
||||
### `player.textTracks() -> TextTrackList`
|
||||
This is the main interface into the text tracks of the player.
|
||||
It return a TextTrackList which lists all the tracks on the player.
|
||||
|
||||
### `player.remoteTextTracks() -> TextTrackList`
|
||||
This is a helper method to get a list of all the tracks that were created from `track` elements or that were added to the player by the `addRemoteTextTrack` method. All these tracks are removeable from the player, where-as not all tracks from `player.textTracks()` are necessarily removeable.
|
||||
|
||||
### `player.remoteTextTrackEls() -> HTMLTrackElementList`
|
||||
Another helper method, this is a list of all the `track` elements associated with the player. Both emulated or otherwise.
|
||||
|
||||
### `player.addTextTrack(String kind, [String label [, String language]]) -> TextTrack`
|
||||
This is based on the [w3c spec API](http://www.w3.org/html/wg/drafts/html/master/embedded-content-0.html#dom-media-addtexttrack) and when given a kind and an optional label and language, will create a new text track for you to use.
|
||||
This method is intended for purely programmatic usage of tracks and has one important limitation:
|
||||
tracks created using this method *cannot* be removed. The native `addTextTrack` does not have a corresponding `removeTextTrack`, so, we actually discourage the usage of this method.
|
||||
|
||||
### `player.addRemoteTextTrack(Object options) -> HTMLTrackElement`
|
||||
This function takes an options object that looks pretty similar to the track element and returns a HTMLTrackElement.
|
||||
This object has a `track` property on it which is the actual TextTrack object.
|
||||
This `TextTrack` object is equivalent to the one that can be returned from `player.addTextTrack` with the added bonus that it can be removed from the player.
|
||||
Internally, video.js will either add a `<track>` element for you, or emulate that depending on whether native text tracks are supported or not.
|
||||
The options available are:
|
||||
* `kind`
|
||||
* `label`
|
||||
* `language` (also `srclang`)
|
||||
* `id`
|
||||
* `src`
|
||||
|
||||
### `player.removeRemoteTextTrack(HTMLTrackElement|TextTrack)`
|
||||
This function takes either an HTMLTrackElement or a TextTrack object and removes it from the player.
|
||||
+4
-182
@@ -1,184 +1,6 @@
|
||||
# Tracks
|
||||
There are currently three types of tracks
|
||||
|
||||
Text Tracks are a function of HTML5 video for providing time triggered text to the viewer. Video.js makes tracks work across all browsers. There are currently five types of tracks:
|
||||
|
||||
- **Subtitles**: Translations of the dialogue in the video for when audio is available but not understood. Subtitles are shown over the video.
|
||||
- **Captions**: Transcription of the dialogue, sound effects, musical cues, and other audio information for when the viewer is deaf/hard of hearing, or the video is muted. Captions are also shown over the video.
|
||||
- **Chapters**: Chapter titles that are used to create navigation within the video. Typically they're in the form of a list of chapters that the viewer can click on to go to a specific chapter.
|
||||
- **Descriptions**: Text descriptions of what's happening in the video for when the video portion isn't available, because the viewer is blind, not using a screen, or driving and about to crash because they're trying to enjoy a video while driving. Descriptions are read by a screen reader or turned into a separate audio track.
|
||||
- **Metadata**: Tracks that have data meant for javascript to parse and do something with. These aren't shown to the user.
|
||||
|
||||
## Creating the Text File
|
||||
Timed text requires a text file in [WebVTT](http://dev.w3.org/html5/webvtt/) format. This format defines a list of "cues" that have a start time, and end time, and text to display. [Microsoft has a builder](https://dev.modern.ie/testdrive/demos/captionmaker/) that can help you get started on the file.
|
||||
|
||||
When creating captions, there's also additional [caption formatting techniques] (http://www.theneitherworld.com/mcpoodle/SCC_TOOLS/DOCS/SCC_FORMAT.HTML#style) that would be good to use, like brackets around sound effects: [ sound effect ]. If you'd like a more in depth style guide for captioning, you can reference the [Captioning Key](http://www.dcmp.org/captioningkey/), but keep in mind not all features are supported by WebVTT or (more likely) the Video.js WebVTT implementation.
|
||||
|
||||
## Adding to Video.js
|
||||
Once you have your WebVTT file created, you can add it to Video.js using the track tag. Put your track tag after all the source elements, and before any fallback content.
|
||||
|
||||
```html
|
||||
<video id="example_video_1" class="video-js"
|
||||
controls preload="auto" width="640" height="264"
|
||||
data-setup='{"example_option":true}'>
|
||||
<source src="http://vjs.zencdn.net/v/oceans.mp4" type="video/mp4" />
|
||||
<source src="http://vjs.zencdn.net/v/oceans.webm" type="video/webm" />
|
||||
<source src="http://vjs.zencdn.net/v/oceans.ogv" type="video/ogg" />
|
||||
|
||||
<track kind="captions" src="http://example.com/path/to/captions.vtt" srclang="en" label="English" default>
|
||||
|
||||
</video>
|
||||
```
|
||||
|
||||
You can also add tracks [programatically](#api).
|
||||
|
||||
## Subtitles from Another Domain
|
||||
Because we're pulling in the text track file via Javascript, the [same-origin policy](http://en.wikipedia.org/wiki/Same_origin_policy) applies. If you'd like to have a player served from one domain,
|
||||
but the text track served from another, you'll need to [enable CORS](http://enable-cors.org/) in order to do so.
|
||||
In addition to enabling CORS on the server serving the text tracks, you will need to add the [`crossorigin` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes) to the video element itself. This attribute has two values `anonymous` and `use-credentials`. Most users will want to use `anonymous` with cross-origin tracks.
|
||||
It can be added to the video element like so:
|
||||
```html
|
||||
<video class="video-js" crossorigin="anonymous">
|
||||
<source src="http://vjs.zencdn.net/v/oceans.mp4" type="video/mp4">
|
||||
<track src="http://example.com/oceans.vtt" kind="captions" srclang="en" label="English">
|
||||
</video>
|
||||
```
|
||||
One thing to be aware of is that in this case the video files themselves will *also* needs CORS headers applied to it. This is because some browsers apply the crossorigin attribute to the video source itself and not just the tracks and is considered a [security concern by the spec](https://html.spec.whatwg.org/multipage/embedded-content.html#security-and-privacy-considerations).
|
||||
|
||||
## Track Attributes
|
||||
Additional settings for track tags.
|
||||
|
||||
### kind
|
||||
One of the five track types listed above. Kind defaults to subtitles if no kind is included.
|
||||
|
||||
### label
|
||||
The label for the track that will be show to the user, for example in a menu that list the different languages available for subtitles.
|
||||
|
||||
### default
|
||||
The default attribute can be used to have a track default to showing. Otherwise the viewer would need to select their language from the captions or subtitles menu.
|
||||
NOTE: For chapters, default is required if you want the chapters menu to show.
|
||||
|
||||
### srclang
|
||||
The two-letter code (valid BCP 47 language tag) for the language of the text track, for example "en" for English. A list of language codes is [available here](languages.md#language-codes).
|
||||
|
||||
## Interacting with Text Tracks
|
||||
### Showing tracks programmatically
|
||||
Some of you would want to turn captions on and off programmatically rather than just forcing the user to do so themselves. This can be easily achieved by modifying the `mode` of the text tracks.
|
||||
The `mode` can be one of three values `disabled`, `hidden`, and `showing`.
|
||||
When a text track's `mode` is `disabled`, the track does not show on screen as the video is playing.
|
||||
When the `mode` is set to `showing`, the track is visible to the viewer and updates while the video is playing.
|
||||
You can change of a particular track like so:
|
||||
```js
|
||||
let tracks = player.textTracks();
|
||||
|
||||
for (let i = 0; i < tracks.length; i++) {
|
||||
let track = tracks[i];
|
||||
|
||||
// find the captions track that's in english
|
||||
if (track.kind === 'captions' && track.language === 'en') {
|
||||
track.mode = 'showing';
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Doing something when a cue becomes active
|
||||
Above, we mentioned that `mode` can also be `hidden`, what this means is that the track will update
|
||||
as the video is playing but it won't be visible to the viewer. This is most useful for `metadata` text tracks.
|
||||
One usecase for metadata text tracks is to have something happen when their cues become active, to do so, you listen to the `cuechange` event on the track. These events fire when the mode is `showing` as well.
|
||||
Here's an example:
|
||||
```js
|
||||
let tracks = player.textTracks();
|
||||
let metadataTrack;
|
||||
|
||||
for (let i = 0; i < tracks.length; i++) {
|
||||
let track = tracks[i];
|
||||
|
||||
// find the metadata track that's labeled ads
|
||||
if (track.kind === 'captions' && track.label === 'ads') {
|
||||
track.mode = 'hidden';
|
||||
// store it for usage outside of the loop
|
||||
metadataTrack = track;
|
||||
}
|
||||
}
|
||||
|
||||
metadataTrack.addEventListener('cuechange', function() {
|
||||
player.ads.startLinearAdMode();
|
||||
});
|
||||
```
|
||||
|
||||
## Emulated Text Tracks
|
||||
By default, video.js will try and use native text tracks if possible and fall back to emulated text tracks if the native functionality is broken or incomplete or non-existent.
|
||||
The Flash tech will always use the emulated text track functionality.
|
||||
The video.js API and TextTrack objects were modeled after the w3c's specification.
|
||||
video.js uses [Mozilla's vtt.js](https://github.com/mozilla/vtt.js) library to parse and display its emulated text tracks.
|
||||
|
||||
If you wanted to disable native text track functionality and force video.js to use emulated text tracks always, you can supply the `nativeTextTrack` option to the tech like so:
|
||||
```js
|
||||
let player = videojs('myvideo', {
|
||||
html5: {
|
||||
nativeTextTrack: false
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Text Track Settings
|
||||
When using emulated Text Tracks, captions will have an additional item in the menu called "caption settings".
|
||||
This allows the viewer of the player to change some styles of how the captions are displayed on screen.
|
||||
|
||||
If you don't want that, you can disable it by turning off the text track settings component and hiding the menu item like so:
|
||||
```js
|
||||
let player = videojs('myvideo', {
|
||||
// make the text track settings dialog not initialize
|
||||
textTrackSettings: false
|
||||
});
|
||||
```
|
||||
```css
|
||||
/* hide the captions settings item from the captions menu */
|
||||
.vjs-texttrack-settings {
|
||||
display: none;
|
||||
}
|
||||
```
|
||||
|
||||
## Text Track Precedence
|
||||
In general, the Descriptions tracks is of lower precedence than captions and subtitles.
|
||||
What this means for you?
|
||||
* If you are using the `default` attribute, videojs will choose the first track that is marked as `default` and turn it on. If There are multiple tracks marked `default`, it will try and turn on the first `captions` or `subtitles` track *before* any `descriptions` tracks.
|
||||
* This only applied to the emulated captions support, native text tracks behavior will change depending on the browser
|
||||
* If you select a given track from the menu, videojs will turn off all the other tracks of the same kind. This may seem like you can have both subtitles and captions turned on at the same time but unfortuantely, at this time we only support one track being displayed at a time.
|
||||
* This means that for emulated text tracks, we'll choose the first captions or subtitles track that is enabled to display.
|
||||
* When native text tracks are supported, we will still disable the other tracks of the same kind but it is possible that multiple text tracks are shown.
|
||||
* If a `descriptions` track is selected and subsequently a `subtitles` or `captions` track is selected, the `descriptions` track is disabled and its menu button is also disabled.
|
||||
* When enabling a track programmatically, there's not much checking that videojs does.
|
||||
* For emulated text tracks, when it's time to display the captions, video.js would choose the first track that's showing, again choosing `subtitles` or `captions` over `descriptions`, if necessary.
|
||||
* For native text tracks, this behavior depends on the browser. Some browsers will let you have multiple text tracks but others will disable all other tracks when a new one is selected.
|
||||
|
||||
## API
|
||||
|
||||
### `player.textTracks() -> TextTrackList`
|
||||
This is the main interface into the text tracks of the player.
|
||||
It return a TextTrackList which lists all the tracks on the player.
|
||||
|
||||
### `player.remoteTextTracks() -> TextTrackList`
|
||||
This is a helper method to get a list of all the tracks that were created from `track` elements or that were added to the player by the `addRemoteTextTrack` method. All these tracks are removeable from the player, where-as not all tracks from `player.textTracks()` are necessarily removeable.
|
||||
|
||||
### `player.remoteTextTrackEls() -> HTMLTrackElementList`
|
||||
Another helper method, this is a list of all the `track` elements associated with the player. Both emulated or otherwise.
|
||||
|
||||
### `player.addTextTrack(String kind, [String label [, String language]]) -> TextTrack`
|
||||
This is based on the [w3c spec API](http://www.w3.org/html/wg/drafts/html/master/embedded-content-0.html#dom-media-addtexttrack) and when given a kind and an optional label and language, will create a new text track for you to use.
|
||||
This method is intended for purely programmatic usage of tracks and has one important limitation:
|
||||
tracks created using this method *cannot* be removed. The native `addTextTrack` does not have a corresponding `removeTextTrack`, so, we actually discourage the usage of this method.
|
||||
|
||||
### `player.addRemoteTextTrack(Object options) -> HTMLTrackElement`
|
||||
This function takes an options object that looks pretty similar to the track element and returns a HTMLTrackElement.
|
||||
This object has a `track` property on it which is the actual TextTrack object.
|
||||
This `TextTrack` object is equivalent to the one that can be returned from `player.addTextTrack` with the added bonus that it can be removed from the player.
|
||||
Internally, video.js will either add a `<track>` element for you, or emulate that depending on whether native text tracks are supported or not.
|
||||
The options available are:
|
||||
* `kind`
|
||||
* `label`
|
||||
* `language` (also `srclang`)
|
||||
* `id`
|
||||
* `src`
|
||||
|
||||
### `player.removeRemoteTextTrack(HTMLTrackElement|TextTrack)`
|
||||
This function takes either an HTMLTrackElement or a TextTrack object and removes it from the player.
|
||||
* [AudioTracks](./audio-tracks.md) - allows the selection of alternative AudioTracks for a video
|
||||
* [VideoTracks](./video-tracks.md) - allows the selection of an alternative VideoTrack for a video
|
||||
* [TextTracks](./text-tracks.md) - Text Tracks are used to display subtitles and captions, and add a menu for navigating between chapters in a video.
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
# Video Tracks
|
||||
|
||||
Video Tracks are a function of HTML5 video for providing a selection of alternative video tracks to the user, so that they can change type of video they want to watch. Video.js makes video tracks work across all browsers. There are currently six types of tracks:
|
||||
|
||||
- **Alternative**: an alternative video representation of the main video track
|
||||
- **Captions**: The main video track with burned in captions
|
||||
- **Main**: the main video track
|
||||
- **Sign**: the main video track with added sign language overlay
|
||||
- **Subtitles**: the main video track with burned in subtitles
|
||||
- **Commentary**: the main video track with burned in commentary
|
||||
|
||||
## Missing Funtionality
|
||||
- It is currently impossible to add VideoTracks in a non-programtic way
|
||||
- Literal switching of VideoTracks for playback is not handled by video.js and must be handled by something else. video.js only stores the track representation
|
||||
- There is currently no UI implementation of VideoTracks
|
||||
|
||||
## Adding to Video.js
|
||||
|
||||
> Right now adding video tracks in the HTML is unsupported. Video Tracks must be added programatically.
|
||||
|
||||
You must add video tracks [programatically](#api) for the time being.
|
||||
|
||||
## Attributes
|
||||
Video Track propertites and settings
|
||||
|
||||
### kind
|
||||
One of the five track types listed above. Kind defaults to empty string if no kind is included, or an invalid kind is used.
|
||||
|
||||
### label
|
||||
The label for the track that will be show to the user, for example in a menu that list the different languages available for video tracks.
|
||||
|
||||
### language
|
||||
The two-letter code (valid BCP 47 language tag) for the language of the video track, for example "en" for English. A list of language codes is [available here](languages.md#language-codes).
|
||||
|
||||
### selected
|
||||
If this track should be playing or not. Trying to select more than one track will cause other tracks to be deselected.
|
||||
|
||||
## Interacting with Video Tracks
|
||||
### Doing something when a track becomes enabled
|
||||
When a new track is enabled (other than the main track) an event is fired on the `VideoTrackList` called `change` you can listen to that event and do something with it.
|
||||
Here's an example:
|
||||
```js
|
||||
// get the current players VideoTrackList object
|
||||
let tracks = player.videoTracks();
|
||||
|
||||
// listen to the change event
|
||||
tracks.addEventListener('change', function() {
|
||||
// get the currently selected track
|
||||
let index = tracks.selectedIndex;
|
||||
let track = tracks[index];
|
||||
|
||||
// print the currently selected track
|
||||
console.log(track.label);
|
||||
});
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### `player.videoTracks() -> VideoTrackList`
|
||||
This is the main interface into the video tracks of the player.
|
||||
It returns an VideoTrackList which is an array like object that contains all the `VideoTrack` on the player.
|
||||
|
||||
### `player.videoTracks().addTrack(VideoTrack)`
|
||||
Add an existing VideoTrack to the players internal list of VideoTracks.
|
||||
|
||||
### `player.videoTracks().removeTrack(VideoTrack)`
|
||||
Remove a track from the VideoTrackList currently on the player. if no track exists this will do nothing.
|
||||
|
||||
### `player.videoTracks().selectedIndex`
|
||||
The current index for the selected track
|
||||
+1
-1
@@ -14,7 +14,7 @@ There are two categories of docs: [Guides](./guides/) and [API docs](./api/). Gu
|
||||
|
||||
* [Options](./guides/options.md) - There are a number of options that can be used to change how the player behaves, starting with the HTML5 media options like autoplay and preload, and expanding to Video.js specific options.
|
||||
|
||||
* [Tracks](./guides/tracks.md) - Text Tracks are used to display subtitles and captions, and add a menu for navigating between chapters in a video.
|
||||
* [Tracks](./guides/tracks.md) - Tracks are used for displaying text information over a video, selecting different audio tracks for a video, or selected different video tracks for a video.
|
||||
|
||||
### Customizing
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
+15
-4
@@ -14,13 +14,24 @@
|
||||
"Unmute": "Geluid aan",
|
||||
"Playback Rate": "Weergavesnelheid",
|
||||
"Subtitles": "Ondertiteling",
|
||||
"subtitles off": "Ondertiteling uit",
|
||||
"Captions": "Ondertiteling",
|
||||
"captions off": "Ondertiteling uit",
|
||||
"subtitles off": "ondertiteling uit",
|
||||
"Captions": "Bijschriften",
|
||||
"captions off": "bijschriften uit",
|
||||
"Chapters": "Hoofdstukken",
|
||||
"Descriptions": "Beschrijvingen",
|
||||
"descriptions off": "beschrijvingen off",
|
||||
"You aborted the media playback": "U hebt de mediaweergave afgebroken.",
|
||||
"A network error caused the media download to fail part-way.": "De mediadownload is mislukt door een netwerkfout.",
|
||||
"The media could not be loaded, either because the server or network failed or because the format is not supported.": "De media kon niet worden geladen, vanwege een server- of netwerkfout of doordat het formaat niet wordt ondersteund.",
|
||||
"The media playback was aborted due to a corruption problem or because the media used features your browser did not support.": "De mediaweergave is afgebroken vanwege beschadigde data of het mediabestand gebruikt functies die niet door uw browser worden ondersteund.",
|
||||
"No compatible source was found for this media.": "Voor deze media is geen ondersteunde bron gevonden."
|
||||
"No compatible source was found for this media.": "Voor deze media is geen ondersteunde bron gevonden.",
|
||||
"Play Video": "Video Afspelen",
|
||||
"Close": "Sluiten",
|
||||
"Modal Window": "Modal Venster",
|
||||
"This is a modal window": "Dit is een modaal venster",
|
||||
"This modal can be closed by pressing the Escape key or activating the close button.": "Dit modaal venster kan gesloten worden door op Escape te drukken of de 'sluiten' knop te activeren.",
|
||||
", opens captions settings dialog": ", opent bijschriften instellingen venster",
|
||||
", opens subtitles settings dialog": ", opent ondertiteling instellingen venster",
|
||||
", opens descriptions settings dialog": ", opent beschrijvingen instellingen venster",
|
||||
", selected": ", selected"
|
||||
}
|
||||
|
||||
+4
-3
@@ -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.7",
|
||||
"version": "5.11.2",
|
||||
"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",
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
@media print {
|
||||
.video-js > *:not(.vjs-tech):not(.vjs-poster) {
|
||||
visibility:hidden;
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,8 @@
|
||||
.vjs-current-time, .vjs-time-divider, .vjs-duration, .vjs-remaining-time,
|
||||
.vjs-playback-rate, .vjs-progress-control,
|
||||
.vjs-mute-control, .vjs-volume-control, .vjs-volume-menu-button,
|
||||
.vjs-chapters-button, .vjs-captions-button, .vjs-subtitles-button { display: none; }
|
||||
.vjs-chapters-button, .vjs-descriptions-button, .vjs-captions-button,
|
||||
.vjs-subtitles-button, .vjs-audio-button { display: none; }
|
||||
}
|
||||
|
||||
// When the player is x-small, display nothing but:
|
||||
@@ -19,7 +20,8 @@
|
||||
.vjs-current-time, .vjs-time-divider, .vjs-duration, .vjs-remaining-time,
|
||||
.vjs-playback-rate,
|
||||
.vjs-mute-control, .vjs-volume-control, .vjs-volume-menu-button,
|
||||
.vjs-chapters-button, .vjs-captions-button, .vjs-subtitles-button { display: none; }
|
||||
.vjs-chapters-button, .vjs-descriptions-button, .vjs-captions-button,
|
||||
.vjs-subtitles-button, .vjs-audio-button { display: none; }
|
||||
}
|
||||
|
||||
|
||||
@@ -33,5 +35,6 @@
|
||||
.vjs-current-time, .vjs-time-divider, .vjs-duration, .vjs-remaining-time,
|
||||
.vjs-playback-rate,
|
||||
.vjs-mute-control, .vjs-volume-control,
|
||||
.vjs-chapters-button, .vjs-captions-button, .vjs-subtitles-button { display: none; }
|
||||
.vjs-chapters-button, .vjs-descriptions-button, .vjs-captions-button,
|
||||
.vjs-subtitles-button .vjs-audio-button { display: none; }
|
||||
}
|
||||
|
||||
@@ -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,10 @@
|
||||
margin: 5px;
|
||||
padding: 3px;
|
||||
min-height: 40px;
|
||||
border: none;
|
||||
}
|
||||
.vjs-caption-settings .vjs-tracksetting label {
|
||||
.vjs-caption-settings .vjs-tracksetting label,
|
||||
.vjs-caption-settings .vjs-tracksetting legend {
|
||||
display: block;
|
||||
width: 100px;
|
||||
margin-bottom: 5px;
|
||||
@@ -50,6 +52,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 +71,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";
|
||||
|
||||
@@ -78,7 +78,7 @@ class ClickableComponent extends Component {
|
||||
el.appendChild(this.controlTextEl_);
|
||||
}
|
||||
|
||||
this.controlText(this.controlText_);
|
||||
this.controlText(this.controlText_, el);
|
||||
|
||||
return this.controlTextEl_;
|
||||
}
|
||||
@@ -86,15 +86,19 @@ class ClickableComponent extends Component {
|
||||
/**
|
||||
* Controls text - both request and localize
|
||||
*
|
||||
* @param {String} text Text for element
|
||||
* @param {String} text Text for element
|
||||
* @param {Element=} el Element to set the title on
|
||||
* @return {String}
|
||||
* @method controlText
|
||||
*/
|
||||
controlText(text) {
|
||||
controlText(text, el=this.el()) {
|
||||
if (!text) return this.controlText_ || 'Need Text';
|
||||
|
||||
const localizedText = this.localize(text);
|
||||
|
||||
this.controlText_ = text;
|
||||
this.controlTextEl_.innerHTML = this.localize(this.controlText_);
|
||||
this.controlTextEl_.innerHTML = localizedText;
|
||||
el.setAttribute('title', localizedText);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
+60
-8
@@ -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.
|
||||
}
|
||||
@@ -1107,7 +1127,7 @@ class Player extends Component {
|
||||
*/
|
||||
handleTechError_() {
|
||||
let error = this.tech_.error();
|
||||
this.error(error && error.code);
|
||||
this.error(error);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1828,7 +1864,7 @@ class Player extends Component {
|
||||
let foundSourceAndTech;
|
||||
let flip = (fn) => (a, b) => fn(b, a);
|
||||
let finder = ([techName, tech], source) => {
|
||||
if (tech.canPlaySource(source)) {
|
||||
if (tech.canPlaySource(source, this.options_[techName.toLowerCase()])) {
|
||||
return {source: source, tech: techName};
|
||||
}
|
||||
};
|
||||
@@ -1903,7 +1939,7 @@ class Player extends Component {
|
||||
} else if (source instanceof Object) {
|
||||
// check if the source has a type and the loaded tech cannot play the source
|
||||
// if there's no type we'll just try the current tech
|
||||
if (source.type && !currentTech.canPlaySource(source)) {
|
||||
if (source.type && !currentTech.canPlaySource(source, this.options_[this.techName_.toLowerCase()])) {
|
||||
// create a source list with the current source and send through
|
||||
// the tech loop to check for a compatible technology
|
||||
this.sourceList_([source]);
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -75,9 +75,10 @@ function FlashRtmpDecorator(Flash) {
|
||||
/**
|
||||
* Check if Flash can handle the source natively
|
||||
* @param {Object} source The source object
|
||||
* @param {Object} options The options passed to the tech
|
||||
* @return {String} 'probably', 'maybe', or '' (empty string)
|
||||
*/
|
||||
Flash.rtmpSourceHandler.canHandleSource = function(source){
|
||||
Flash.rtmpSourceHandler.canHandleSource = function(source, options){
|
||||
let can = Flash.rtmpSourceHandler.canPlayType(source.type);
|
||||
|
||||
if (can) {
|
||||
|
||||
+18
-3
@@ -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);
|
||||
@@ -369,9 +383,10 @@ Flash.nativeSourceHandler.canPlayType = function(type){
|
||||
* Check Flash can handle the source natively
|
||||
*
|
||||
* @param {Object} source The source object
|
||||
* @param {Object} options The options passed to the tech
|
||||
* @return {String} 'probably', 'maybe', or '' (empty string)
|
||||
*/
|
||||
Flash.nativeSourceHandler.canHandleSource = function(source){
|
||||
Flash.nativeSourceHandler.canHandleSource = function(source, options){
|
||||
var type;
|
||||
|
||||
function guessMimeType(src) {
|
||||
@@ -456,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
|
||||
|
||||
+69
-4
@@ -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
|
||||
@@ -944,9 +1008,10 @@ Html5.nativeSourceHandler.canPlayType = function(type){
|
||||
* Check if the video element can handle the source natively
|
||||
*
|
||||
* @param {Object} source The source object
|
||||
* @param {Object} options The options passed to the tech
|
||||
* @return {String} 'probably', 'maybe', or '' (empty string)
|
||||
*/
|
||||
Html5.nativeSourceHandler.canHandleSource = function(source){
|
||||
Html5.nativeSourceHandler.canHandleSource = function(source, options){
|
||||
var match, ext;
|
||||
|
||||
// If a type was provided we should rely on that
|
||||
|
||||
@@ -726,16 +726,17 @@ Tech.withSourceHandlers = function(_Tech){
|
||||
/*
|
||||
* Return the first source handler that supports the source
|
||||
* TODO: Answer question: should 'probably' be prioritized over 'maybe'
|
||||
* @param {Object} source The source object
|
||||
* @param {Object} source The source object
|
||||
* @param {Object} options The options passed to the tech
|
||||
* @returns {Object} The first source handler that supports the source
|
||||
* @returns {null} Null if no source handler is found
|
||||
*/
|
||||
_Tech.selectSourceHandler = function(source){
|
||||
_Tech.selectSourceHandler = function(source, options){
|
||||
let handlers = _Tech.sourceHandlers || [];
|
||||
let can;
|
||||
|
||||
for (let i = 0; i < handlers.length; i++) {
|
||||
can = handlers[i].canHandleSource(source);
|
||||
can = handlers[i].canHandleSource(source, options);
|
||||
|
||||
if (can) {
|
||||
return handlers[i];
|
||||
@@ -748,13 +749,14 @@ Tech.withSourceHandlers = function(_Tech){
|
||||
/*
|
||||
* Check if the tech can support the given source
|
||||
* @param {Object} srcObj The source object
|
||||
* @param {Object} options The options passed to the tech
|
||||
* @return {String} 'probably', 'maybe', or '' (empty string)
|
||||
*/
|
||||
_Tech.canPlaySource = function(srcObj){
|
||||
let sh = _Tech.selectSourceHandler(srcObj);
|
||||
_Tech.canPlaySource = function(srcObj, options){
|
||||
let sh = _Tech.selectSourceHandler(srcObj, options);
|
||||
|
||||
if (sh) {
|
||||
return sh.canHandleSource(srcObj);
|
||||
return sh.canHandleSource(srcObj, options);
|
||||
}
|
||||
|
||||
return '';
|
||||
@@ -792,7 +794,7 @@ Tech.withSourceHandlers = function(_Tech){
|
||||
* @return {Tech} self
|
||||
*/
|
||||
_Tech.prototype.setSource = function(source){
|
||||
let sh = _Tech.selectSourceHandler(source);
|
||||
let sh = _Tech.selectSourceHandler(source, this.options_);
|
||||
|
||||
if (!sh) {
|
||||
// Fall back to a native source hander when unsupported sources are
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
import log from './log.js';
|
||||
|
||||
/**
|
||||
* Object containing the default behaviors for available handler methods.
|
||||
*
|
||||
* @private
|
||||
* @type {Object}
|
||||
*/
|
||||
const defaultBehaviors = {
|
||||
get(obj, key) {
|
||||
return obj[key];
|
||||
},
|
||||
set(obj, key, value) {
|
||||
obj[key] = value;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Expose private objects publicly using a Proxy to log deprecation warnings.
|
||||
*
|
||||
* Browsers that do not support Proxy objects will simply return the `target`
|
||||
* object, so it can be directly exposed.
|
||||
*
|
||||
* @param {Object} target The target object.
|
||||
* @param {Object} messages Messages to display from a Proxy. Only operations
|
||||
* with an associated message will be proxied.
|
||||
* @param {String} [messages.get]
|
||||
* @param {String} [messages.set]
|
||||
* @return {Object} A Proxy if supported or the `target` argument.
|
||||
*/
|
||||
export default (target, messages={}) => {
|
||||
if (typeof Proxy === 'function') {
|
||||
let handler = {};
|
||||
|
||||
// Build a handler object based on those keys that have both messages
|
||||
// and default behaviors.
|
||||
Object.keys(messages).forEach(key => {
|
||||
if (defaultBehaviors.hasOwnProperty(key)) {
|
||||
handler[key] = function() {
|
||||
log.warn(messages[key]);
|
||||
return defaultBehaviors[key].apply(this, arguments);
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
return new Proxy(target, handler);
|
||||
}
|
||||
return target;
|
||||
};
|
||||
+71
-53
@@ -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;
|
||||
|
||||
+4
-12
@@ -16,7 +16,6 @@ import TextTrack from './tracks/text-track.js';
|
||||
import AudioTrack from './tracks/audio-track.js';
|
||||
import VideoTrack from './tracks/video-track.js';
|
||||
|
||||
import assign from 'object.assign';
|
||||
import { createTimeRanges } from './utils/time-ranges.js';
|
||||
import formatTime from './utils/format-time.js';
|
||||
import log from './utils/log.js';
|
||||
@@ -25,7 +24,6 @@ import * as browser from './utils/browser.js';
|
||||
import * as Url from './utils/url.js';
|
||||
import extendFn from './extend.js';
|
||||
import merge from 'lodash-compat/object/merge';
|
||||
import createDeprecationProxy from './utils/create-deprecation-proxy.js';
|
||||
import xhr from 'xhr';
|
||||
|
||||
// Include the built-in techs
|
||||
@@ -153,21 +151,15 @@ videojs.options = Player.prototype.options_;
|
||||
* @mixes videojs
|
||||
* @method getPlayers
|
||||
*/
|
||||
videojs.getPlayers = function() {
|
||||
return Player.players;
|
||||
};
|
||||
videojs.getPlayers = () => Player.players;
|
||||
|
||||
/**
|
||||
* For backward compatibility, expose players object.
|
||||
* Expose players object.
|
||||
*
|
||||
* @deprecated
|
||||
* @memberOf videojs
|
||||
* @property {Object|Proxy} players
|
||||
* @property {Object} players
|
||||
*/
|
||||
videojs.players = createDeprecationProxy(Player.players, {
|
||||
get: 'Access to videojs.players is deprecated; use videojs.getPlayers instead',
|
||||
set: 'Modification of videojs.players is deprecated'
|
||||
});
|
||||
videojs.players = Player.players;
|
||||
|
||||
/**
|
||||
* Get a component class object by name
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'es6-shim';
|
||||
import document from 'global/document';
|
||||
import window from 'global/window';
|
||||
import sinon from 'sinon';
|
||||
|
||||
@@ -4,7 +4,7 @@ import TestHelpers from './test-helpers.js';
|
||||
q.module('Button');
|
||||
|
||||
test('should localize its text', function(){
|
||||
expect(2);
|
||||
expect(3);
|
||||
|
||||
var player, testButton, el;
|
||||
|
||||
@@ -22,5 +22,6 @@ test('should localize its text', function(){
|
||||
el = testButton.createEl();
|
||||
|
||||
ok(el.nodeName.toLowerCase().match('button'));
|
||||
ok(el.innerHTML.match('Juego'));
|
||||
ok(el.innerHTML.match(/vjs-control-text"?>Juego/));
|
||||
equal(el.getAttribute('title'), 'Juego');
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
|
||||
@@ -8,16 +8,16 @@ test('Flash.canPlaySource', function() {
|
||||
var canPlaySource = Flash.canPlaySource;
|
||||
|
||||
// Supported
|
||||
ok(canPlaySource({ type: 'video/mp4; codecs=avc1.42E01E,mp4a.40.2' }), 'codecs supported');
|
||||
ok(canPlaySource({ type: 'video/mp4' }), 'video/mp4 supported');
|
||||
ok(canPlaySource({ type: 'video/x-flv' }), 'video/x-flv supported');
|
||||
ok(canPlaySource({ type: 'video/flv' }), 'video/flv supported');
|
||||
ok(canPlaySource({ type: 'video/m4v' }), 'video/m4v supported');
|
||||
ok(canPlaySource({ type: 'VIDEO/FLV' }), 'capitalized mime type');
|
||||
ok(canPlaySource({ type: 'video/mp4; codecs=avc1.42E01E,mp4a.40.2' }, {}), 'codecs supported');
|
||||
ok(canPlaySource({ type: 'video/mp4' }, {}), 'video/mp4 supported');
|
||||
ok(canPlaySource({ type: 'video/x-flv' }, {}), 'video/x-flv supported');
|
||||
ok(canPlaySource({ type: 'video/flv' }, {}), 'video/flv supported');
|
||||
ok(canPlaySource({ type: 'video/m4v' }, {}), 'video/m4v supported');
|
||||
ok(canPlaySource({ type: 'VIDEO/FLV' }, {}), 'capitalized mime type');
|
||||
|
||||
// Not supported
|
||||
ok(!canPlaySource({ type: 'video/webm; codecs="vp8, vorbis"' }));
|
||||
ok(!canPlaySource({ type: 'video/webm' }));
|
||||
ok(!canPlaySource({ type: 'video/webm; codecs="vp8, vorbis"' }, {}));
|
||||
ok(!canPlaySource({ type: 'video/webm' }, {}));
|
||||
});
|
||||
|
||||
test('currentTime', function() {
|
||||
@@ -147,10 +147,10 @@ test('canPlayType should select the correct types to play', function () {
|
||||
test('canHandleSource should be able to work with src objects without a type', function () {
|
||||
let canHandleSource = Flash.nativeSourceHandler.canHandleSource;
|
||||
|
||||
equal('maybe', canHandleSource({ src: 'test.video.mp4' }), 'should guess that it is a mp4 video');
|
||||
equal('maybe', canHandleSource({ src: 'test.video.m4v' }), 'should guess that it is a m4v video');
|
||||
equal('maybe', canHandleSource({ src: 'test.video.flv' }), 'should guess that it is a flash video');
|
||||
equal('', canHandleSource({ src: 'test.video.wgg' }), 'should return empty string if it can not play the video');
|
||||
equal('maybe', canHandleSource({ src: 'test.video.mp4' }, {}), 'should guess that it is a mp4 video');
|
||||
equal('maybe', canHandleSource({ src: 'test.video.m4v' }, {}), 'should guess that it is a m4v video');
|
||||
equal('maybe', canHandleSource({ src: 'test.video.flv' }, {}), 'should guess that it is a flash video');
|
||||
equal('', canHandleSource({ src: 'test.video.wgg' }, {}), 'should return empty string if it can not play the video');
|
||||
});
|
||||
|
||||
test('seekable', function() {
|
||||
@@ -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() {
|
||||
|
||||
@@ -190,16 +190,16 @@ test('native source handler canHandleSource', function(){
|
||||
|
||||
var canHandleSource = Html5.nativeSourceHandler.canHandleSource;
|
||||
|
||||
equal(canHandleSource({ type: 'video/mp4', src: 'video.flv' }), 'maybe', 'Native source handler reported type support');
|
||||
equal(canHandleSource({ src: 'http://www.example.com/video.mp4' }), 'maybe', 'Native source handler reported extension support');
|
||||
equal(canHandleSource({ src: 'https://example.com/video.sd.mp4?s=foo&token=bar' }), 'maybe', 'Native source handler reported extension support');
|
||||
equal(canHandleSource({ src: 'https://example.com/video.sd.mp4?s=foo' }), 'maybe', 'Native source handler reported extension support');
|
||||
equal(canHandleSource({ type: 'video/mp4', src: 'video.flv' }, {}), 'maybe', 'Native source handler reported type support');
|
||||
equal(canHandleSource({ src: 'http://www.example.com/video.mp4' }, {}), 'maybe', 'Native source handler reported extension support');
|
||||
equal(canHandleSource({ src: 'https://example.com/video.sd.mp4?s=foo&token=bar' }, {}), 'maybe', 'Native source handler reported extension support');
|
||||
equal(canHandleSource({ src: 'https://example.com/video.sd.mp4?s=foo' }, {}), 'maybe', 'Native source handler reported extension support');
|
||||
|
||||
// Test for issue videojs/video.js#1785 and other potential failures
|
||||
equal(canHandleSource({ src: '' }), '', 'Native source handler handled empty src');
|
||||
equal(canHandleSource({}), '', 'Native source handler handled empty object');
|
||||
equal(canHandleSource({ src: 'foo' }), '', 'Native source handler handled bad src');
|
||||
equal(canHandleSource({ type: 'foo' }), '', 'Native source handler handled bad type');
|
||||
equal(canHandleSource({ src: '' }, {}), '', 'Native source handler handled empty src');
|
||||
equal(canHandleSource({}, {}), '', 'Native source handler handled empty object');
|
||||
equal(canHandleSource({ src: 'foo' }, {}), '', 'Native source handler handled bad src');
|
||||
equal(canHandleSource({ type: 'foo' }, {}), '', 'Native source handler handled bad type');
|
||||
|
||||
// Reset test video canPlayType
|
||||
Html5.TEST_VID.canPlayType = origCPT;
|
||||
|
||||
@@ -185,7 +185,8 @@ test('should add the source handler interface to a tech', function(){
|
||||
}
|
||||
return '';
|
||||
},
|
||||
canHandleSource: function(source){
|
||||
canHandleSource: function(source, options){
|
||||
strictEqual(tech.options_, options, 'the tech options were passed to the source handler canHandleSource');
|
||||
if (source.type !=='no-support') {
|
||||
return 'probably';
|
||||
}
|
||||
@@ -194,7 +195,7 @@ test('should add the source handler interface to a tech', function(){
|
||||
handleSource: function(s, t, o){
|
||||
strictEqual(tech, t, 'the tech instance was passed to the source handler');
|
||||
strictEqual(sourceA, s, 'the tech instance was passed to the source handler');
|
||||
strictEqual(tech.options_, o, 'the tech options were passed to the source handler');
|
||||
strictEqual(tech.options_, o, 'the tech options were passed to the source handler handleSource');
|
||||
return new handlerInternalState();
|
||||
}
|
||||
};
|
||||
@@ -203,7 +204,7 @@ test('should add the source handler interface to a tech', function(){
|
||||
canPlayType: function(type){
|
||||
return ''; // no support
|
||||
},
|
||||
canHandleSource: function(source){
|
||||
canHandleSource: function(source, options){
|
||||
return ''; // no support
|
||||
},
|
||||
handleSource: function(source, tech, options){
|
||||
@@ -218,16 +219,16 @@ test('should add the source handler interface to a tech', function(){
|
||||
strictEqual(MyTech.sourceHandlers[0], handlerTwo, 'handlerTwo was registered at the correct index (0)');
|
||||
|
||||
// Test handler selection
|
||||
strictEqual(MyTech.selectSourceHandler(sourceA), handlerOne, 'handlerOne was selected to handle the valid source');
|
||||
strictEqual(MyTech.selectSourceHandler(sourceB), null, 'no handler was selected to handle the invalid source');
|
||||
strictEqual(MyTech.selectSourceHandler(sourceA, tech.options_), handlerOne, 'handlerOne was selected to handle the valid source');
|
||||
strictEqual(MyTech.selectSourceHandler(sourceB, tech.options_), null, 'no handler was selected to handle the invalid source');
|
||||
|
||||
// Test canPlayType return values
|
||||
strictEqual(MyTech.canPlayType(sourceA.type), 'probably', 'the Tech returned probably for the valid source');
|
||||
strictEqual(MyTech.canPlayType(sourceB.type), '', 'the Tech returned an empty string for the invalid source');
|
||||
|
||||
// Test canPlaySource return values
|
||||
strictEqual(MyTech.canPlaySource(sourceA), 'probably', 'the Tech returned probably for the valid source');
|
||||
strictEqual(MyTech.canPlaySource(sourceB), '', 'the Tech returned an empty string for the invalid source');
|
||||
strictEqual(MyTech.canPlaySource(sourceA, tech.options_), 'probably', 'the Tech returned probably for the valid source');
|
||||
strictEqual(MyTech.canPlaySource(sourceB, tech.options_), '', 'the Tech returned an empty string for the invalid source');
|
||||
|
||||
tech.addRemoteTextTrack({});
|
||||
tech.addRemoteTextTrack({});
|
||||
@@ -381,7 +382,7 @@ test('Tech#setSource clears currentSource_ after repeated loadstart', function()
|
||||
canPlayType: function(type) {
|
||||
return true;
|
||||
},
|
||||
canHandleSource: function(source) {
|
||||
canHandleSource: function(source, options) {
|
||||
return true;
|
||||
},
|
||||
handleSource: function(source, tech, options) {
|
||||
|
||||
@@ -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,45 +0,0 @@
|
||||
import createDeprecationProxy from '../../../src/js/utils/create-deprecation-proxy.js';
|
||||
import log from '../../../src/js/utils/log.js';
|
||||
|
||||
const proxySupported = typeof Proxy === 'function';
|
||||
|
||||
test('should return a Proxy object when supported or the target object by reference', function() {
|
||||
let target = {foo: 1};
|
||||
let subject = createDeprecationProxy(target, {
|
||||
get: 'get message',
|
||||
set: 'set message'
|
||||
});
|
||||
|
||||
// Testing for a Proxy is really difficult because Proxy objects by their
|
||||
// nature disguise the fact that they are in fact Proxy objects. So, this
|
||||
// tests that the log.warn method gets called on property get/set operations
|
||||
// to detect the Proxy.
|
||||
if (proxySupported) {
|
||||
sinon.stub(log, 'warn');
|
||||
|
||||
subject.foo; // Triggers a "get"
|
||||
subject.foo = 2; // Triggers a "set"
|
||||
|
||||
equal(log.warn.callCount, 2, 'proxied operations cause deprecation warnings');
|
||||
ok(log.warn.calledWith('get message'), 'proxied get logs expected message');
|
||||
ok(log.warn.calledWith('set message'), 'proxied set logs expected message');
|
||||
|
||||
log.warn.restore();
|
||||
} else {
|
||||
strictEqual(target, subject, 'identical to target');
|
||||
}
|
||||
});
|
||||
|
||||
// Tests run only in Proxy-supporting environments.
|
||||
if (proxySupported) {
|
||||
test('no deprecation warning is logged for operations without a message', function() {
|
||||
let subject = createDeprecationProxy({}, {
|
||||
get: 'get message'
|
||||
});
|
||||
|
||||
sinon.stub(log, 'warn');
|
||||
subject.foo = 'bar'; // Triggers a "set," but not a "get"
|
||||
equal(log.warn.callCount, 0, 'no deprecation warning expected');
|
||||
log.warn.restore();
|
||||
});
|
||||
}
|
||||
@@ -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']);
|
||||
});
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário