@vidispine/vdt-videojs 21.4.0-pre.2 → 22.1.0-pre.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/deprecated-app/README.md +21 -0
- package/{demo.html → deprecated-app/index.html} +1 -1
- package/{demo.js → deprecated-app/index.js} +69 -41
- package/{samples → deprecated-app/samples}/birds-es.vvt +0 -0
- package/{samples → deprecated-app/samples}/birds.vvt +0 -0
- package/{tests.js → deprecated-app/tests.js} +87 -54
- package/{lib/style.css → dist/index.css} +621 -6
- package/dist/index.es.js +2099 -0
- package/dist/index.js +2112 -0
- package/{lib → dist}/index.umd.js +910 -2039
- package/package.json +29 -85
- package/rollup.config.js +54 -0
- package/src/constants.js +1 -1
- package/src/externalControls.js +14 -18
- package/src/helpOverlay.js +12 -16
- package/src/helpers.js +3 -3
- package/src/index.js +3 -9
- package/src/index.stories.mdx +59 -0
- package/src/menu.api.stories.mdx +59 -0
- package/src/menu.js +23 -19
- package/src/{menu.example.md → menu.usage.stories.mdx} +31 -21
- package/src/osd.js +24 -18
- package/src/player.api.stories.mdx +120 -0
- package/src/player.js +157 -108
- package/src/player.scss +2 -0
- package/src/{player.example.md → player.usage.stories.mdx} +18 -8
- package/src/seekBar.js +85 -48
- package/src/timeCodeDisplay.js +39 -31
- package/src/videoTime.js +4 -4
- package/build.js +0 -233
- package/lib/index.cjs.js +0 -3241
- package/lib/index.esm.js +0 -3228
- package/lib/package.json +0 -13
- package/lib/src/constants.js +0 -51
- package/lib/src/externalControls.js +0 -307
- package/lib/src/helpOverlay.js +0 -106
- package/lib/src/helpers.js +0 -34
- package/lib/src/index.js +0 -13
- package/lib/src/menu.js +0 -365
- package/lib/src/osd.js +0 -91
- package/lib/src/player.js +0 -943
- package/lib/src/seekBar.js +0 -833
- package/lib/src/timeCodeDisplay.js +0 -253
- package/lib/src/videoTime.js +0 -66
- package/log.js +0 -24
- package/src/_index.stories.js +0 -24
- package/src/externalControls.stories.js +0 -6
- package/src/helpOverlay.stories.js +0 -6
- package/src/menu.classMethods.md +0 -47
- package/src/player.classMethods.md +0 -108
- package/src/player.stories.js +0 -14
- package/src/seekBar.stories.js +0 -8
- package/tmp/player.css +0 -1
|
@@ -1,112 +1,55 @@
|
|
|
1
1
|
(function (global, factory) {
|
|
2
|
-
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('video.js/dist/alt/video.core.min')
|
|
3
|
-
typeof define === 'function' && define.amd ? define(['exports', 'video.js/dist/alt/video.core.min'
|
|
4
|
-
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.vdtVideojs = {}, global.
|
|
5
|
-
})(this, (function (exports,
|
|
2
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('mousetrap'), require('video.js/dist/alt/video.core.min')) :
|
|
3
|
+
typeof define === 'function' && define.amd ? define(['exports', 'mousetrap', 'video.js/dist/alt/video.core.min'], factory) :
|
|
4
|
+
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.vdtVideojs = {}, global.mousetrap, global.videojs));
|
|
5
|
+
})(this, (function (exports, mousetrap, videojs) { 'use strict';
|
|
6
6
|
|
|
7
7
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
8
8
|
|
|
9
|
-
var videojs__default = /*#__PURE__*/_interopDefaultLegacy(videojs);
|
|
10
9
|
var mousetrap__default = /*#__PURE__*/_interopDefaultLegacy(mousetrap);
|
|
10
|
+
var videojs__default = /*#__PURE__*/_interopDefaultLegacy(videojs);
|
|
11
11
|
|
|
12
12
|
var name = "@vidispine/vdt-videojs";
|
|
13
|
-
var version = "
|
|
13
|
+
var version = "22.1.0-pre.1";
|
|
14
14
|
var license = "UNLICENSED";
|
|
15
|
-
var main = "
|
|
16
|
-
var module = "
|
|
15
|
+
var main = "dist/index.js";
|
|
16
|
+
var module = "dist/index.es.js";
|
|
17
|
+
var browser = "dist/index.umd.js";
|
|
17
18
|
var author = "Oto Inša <otoinsa@bertelsmann.de>";
|
|
18
19
|
var scripts = {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
"build:watch": "node ./build.js --watch",
|
|
24
|
-
"build:demo": "rm -rf ./demo/ && parcel build ./demo.html --out-file index.html --out-dir ./demo --no-source-maps --public-url ./",
|
|
25
|
-
docs: "jsdoc ./src/player.js -d ./docs/"
|
|
26
|
-
};
|
|
27
|
-
var devDependencies = {
|
|
28
|
-
"@babel/core": "^7.7.7",
|
|
29
|
-
"babel-plugin-transform-runtime": "^6.23.0",
|
|
30
|
-
chokidar: "^3.3.1",
|
|
31
|
-
colors: "^1.4.0",
|
|
32
|
-
"parcel-bundler": "^1.12.4",
|
|
33
|
-
rollup: "^2.20.0",
|
|
34
|
-
"rollup-plugin-json": "^4.0.0",
|
|
35
|
-
sass: "^1.24.3",
|
|
36
|
-
"strip-comments": "^2.0.1"
|
|
20
|
+
build: "rm -rf dist/ && rollup -c",
|
|
21
|
+
"build:watch": "rm -rf dist/*.js* && rollup -c -w --environment DEVELOPMENT",
|
|
22
|
+
lint: "eslint \"./{src/**/*,*}.{js,md}\"",
|
|
23
|
+
"lint:fix": "yarn lint --fix"
|
|
37
24
|
};
|
|
38
25
|
var dependencies = {
|
|
39
26
|
mousetrap: "^1.6.3",
|
|
40
27
|
"video.js": "^7.6.6"
|
|
41
28
|
};
|
|
29
|
+
var devDependencies = {
|
|
30
|
+
"@babel/core": "^7.17.0",
|
|
31
|
+
"@rollup/plugin-babel": "^5.3.0",
|
|
32
|
+
"@rollup/plugin-commonjs": "^21.0.1",
|
|
33
|
+
"@rollup/plugin-json": "^4.1.0",
|
|
34
|
+
"@rollup/plugin-node-resolve": "^13.1.3",
|
|
35
|
+
"@vidispine/eslint-config-base": "^22.1.0-pre.1",
|
|
36
|
+
"@vidispine/eslint-config-storybook": "*",
|
|
37
|
+
"babel-plugin-transform-runtime": "^6.23.0",
|
|
38
|
+
rollup: "^2.67.0",
|
|
39
|
+
"rollup-plugin-cleanup": "^3.2.1",
|
|
40
|
+
"rollup-plugin-peer-deps-external": "^2.2.4",
|
|
41
|
+
"rollup-plugin-sass": "^1.2.10"
|
|
42
|
+
};
|
|
42
43
|
var browserslist = [
|
|
43
44
|
"since 2017-06"
|
|
44
45
|
];
|
|
45
|
-
var
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"Borrowed styling ideas from a popular online video platform",
|
|
50
|
-
"Visual feedback gizmo as hotkey feedback",
|
|
51
|
-
"Subtitle support (VVT)",
|
|
52
|
-
"Persistance - volume level",
|
|
53
|
-
"Custom timecode display (SMPTE)",
|
|
54
|
-
"Frame forward / frame backward 6unctionality"
|
|
55
|
-
],
|
|
56
|
-
"0.1.3": [
|
|
57
|
-
"Renamed 'subtitles off' to just 'off'",
|
|
58
|
-
"Timecode SMPTE - current time in SMPTE with input capabilities",
|
|
59
|
-
"Timecode SMPTE - total video duration timecode (read-only)",
|
|
60
|
-
"Settings persistance - storing wether subtitles should be on and the selected language as well"
|
|
61
|
-
],
|
|
62
|
-
"0.1.4": [
|
|
63
|
-
"Subtitles toggle hotkey - c",
|
|
64
|
-
"Now accepts Blob as subtitles source file",
|
|
65
|
-
"Timecode input improvements",
|
|
66
|
-
"Screenshot button with currentTime callback",
|
|
67
|
-
"Moved OSD in its own class"
|
|
68
|
-
],
|
|
69
|
-
"0.1.6": [
|
|
70
|
-
"Help overlay for keyboard controls",
|
|
71
|
-
"External player controls component (js, React)",
|
|
72
|
-
"External seek-bar component (js, React)"
|
|
73
|
-
],
|
|
74
|
-
"0.1.7": [
|
|
75
|
-
"In / Out markers for seek bar"
|
|
76
|
-
],
|
|
77
|
-
"0.1.8": [
|
|
78
|
-
"External TimeCodeDisplay support for player"
|
|
79
|
-
],
|
|
80
|
-
"0.1.9": [
|
|
81
|
-
"Multiple regions with annotations for SeekBar"
|
|
82
|
-
],
|
|
83
|
-
"0.2.2": [
|
|
84
|
-
"Overall version bump (improvements)"
|
|
85
|
-
],
|
|
86
|
-
"0.3.0": [
|
|
87
|
-
"controlsBelowPlayer - reactive option",
|
|
88
|
-
"onDark - used in conjuction with controlsBelowPlayer for dark backgrounds",
|
|
89
|
-
"Bug fixes, convenience class methods"
|
|
90
|
-
],
|
|
91
|
-
"0.3.1": [
|
|
92
|
-
"SeekBar - Seek animation, dark mode improvements",
|
|
93
|
-
"Bug fixes, refactor & code sharing improvements"
|
|
94
|
-
],
|
|
95
|
-
"0.5.3": [
|
|
96
|
-
"vdt-videojs now provides a commonjs module with named exports"
|
|
97
|
-
],
|
|
98
|
-
"0.6.1": [
|
|
99
|
-
"Internal refactor before splitting main features into videojs plugins",
|
|
100
|
-
"More bugfixes"
|
|
46
|
+
var eslintConfig = {
|
|
47
|
+
"extends": [
|
|
48
|
+
"@vidispine/eslint-config-base",
|
|
49
|
+
"@vidispine/eslint-config-storybook"
|
|
101
50
|
]
|
|
102
51
|
};
|
|
103
|
-
var
|
|
104
|
-
"Timecode offset capabilities - i.e. start time from 10:00:00:00"
|
|
105
|
-
];
|
|
106
|
-
var backlog = [
|
|
107
|
-
"External player controls component",
|
|
108
|
-
"Check for hijacked hotkeys and player focus"
|
|
109
|
-
];
|
|
52
|
+
var prettier = "@vidispine/prettier-config";
|
|
110
53
|
var pkgInfo = {
|
|
111
54
|
name: name,
|
|
112
55
|
version: version,
|
|
@@ -114,565 +57,295 @@
|
|
|
114
57
|
"private": false,
|
|
115
58
|
main: main,
|
|
116
59
|
module: module,
|
|
60
|
+
browser: browser,
|
|
117
61
|
author: author,
|
|
118
62
|
scripts: scripts,
|
|
119
|
-
devDependencies: devDependencies,
|
|
120
63
|
dependencies: dependencies,
|
|
64
|
+
devDependencies: devDependencies,
|
|
121
65
|
browserslist: browserslist,
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
backlog: backlog
|
|
66
|
+
eslintConfig: eslintConfig,
|
|
67
|
+
prettier: prettier
|
|
125
68
|
};
|
|
126
69
|
|
|
127
70
|
const defaults = Object.freeze({
|
|
128
|
-
frameRate:
|
|
71
|
+
frameRate: 30000 / 1001,
|
|
129
72
|
jumpSeconds: 10,
|
|
130
|
-
inactivityTimeout: 1200,
|
|
131
|
-
audioInactivityTimeout: 0
|
|
73
|
+
inactivityTimeout: 1200,
|
|
74
|
+
audioInactivityTimeout: 0
|
|
132
75
|
});
|
|
133
|
-
|
|
134
76
|
const osd = Object.freeze({
|
|
135
77
|
play: 0,
|
|
136
78
|
pause: 1,
|
|
137
79
|
volchange: 2,
|
|
138
80
|
jumpForward: 3,
|
|
139
|
-
jumpBackward: 4
|
|
81
|
+
jumpBackward: 4
|
|
140
82
|
});
|
|
141
|
-
|
|
142
83
|
const settings = Object.freeze({
|
|
143
84
|
volume: 'volume-setting',
|
|
144
85
|
subLang: 'subtitles-language',
|
|
145
|
-
subs: 'subtitles-enabled'
|
|
86
|
+
subs: 'subtitles-enabled'
|
|
146
87
|
});
|
|
147
|
-
|
|
148
88
|
const classNames = Object.freeze({
|
|
149
89
|
poster: 'has-poster',
|
|
150
90
|
subtitles: 'has-subtitles',
|
|
151
91
|
subtitlesActive: 'subtitles-active',
|
|
152
92
|
onDark: 'on-dark',
|
|
153
|
-
loading: 'loading'
|
|
93
|
+
loading: 'loading'
|
|
154
94
|
});
|
|
155
|
-
|
|
156
95
|
const colors = Object.freeze({
|
|
157
96
|
gray: '#787878',
|
|
158
|
-
light: 'rgba(255,255,255,.75)'
|
|
97
|
+
light: 'rgba(255,255,255,.75)'
|
|
159
98
|
});
|
|
160
|
-
|
|
161
99
|
const packageInfo = Object.freeze({
|
|
162
100
|
name: pkgInfo.name.split('/')[1],
|
|
163
|
-
vendor: pkgInfo.name.split('/')[0]
|
|
101
|
+
vendor: pkgInfo.name.split('/')[0]
|
|
164
102
|
});
|
|
165
|
-
|
|
166
103
|
const constants$2 = Object.freeze({
|
|
167
104
|
defaults,
|
|
168
105
|
settings,
|
|
169
106
|
classNames,
|
|
170
107
|
colors,
|
|
171
108
|
osd,
|
|
172
|
-
packageInfo
|
|
109
|
+
packageInfo
|
|
173
110
|
});
|
|
174
111
|
|
|
175
112
|
function truncate(input, len) {
|
|
176
|
-
if (input.length > len) return
|
|
113
|
+
if (input.length > len) return "".concat(input.substring(0, len), "...");
|
|
177
114
|
return input;
|
|
178
115
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
/*
|
|
182
|
-
Make certain component props React-ive
|
|
183
|
-
by being able to call respective component .handleNewProps()
|
|
184
|
-
method in react wrappers
|
|
185
|
-
*/
|
|
186
116
|
function reactiveSetters() {
|
|
187
|
-
// will try to find a matching setter in context
|
|
188
|
-
// TODO - switch to for loop for more efficient updates
|
|
189
117
|
function handleNewProps(props) {
|
|
190
118
|
if (typeof props === 'object') {
|
|
191
119
|
const keys = Object.getOwnPropertyNames(props);
|
|
192
120
|
const proto = Object.getPrototypeOf(this);
|
|
193
|
-
keys.forEach(
|
|
194
|
-
// check for own setters / getters
|
|
121
|
+
keys.forEach(key => {
|
|
195
122
|
const descriptor = Object.getOwnPropertyDescriptor(proto, key);
|
|
196
|
-
|
|
197
|
-
if (descriptor && descriptor.set) { // if a setter is defined, apply the prop
|
|
123
|
+
if (descriptor && descriptor.set) {
|
|
198
124
|
this[key] = props[key];
|
|
199
125
|
}
|
|
200
126
|
});
|
|
201
127
|
}
|
|
202
128
|
}
|
|
203
|
-
|
|
204
|
-
// extends a context with handleNewProps method
|
|
205
129
|
this.handleNewProps = handleNewProps;
|
|
206
130
|
}
|
|
207
|
-
|
|
208
|
-
// an elegant way to prevent xss attacks
|
|
209
|
-
function sanitize(str) {
|
|
131
|
+
function sanitize(str) {
|
|
210
132
|
const temp = document.createElement('div');
|
|
211
133
|
temp.textContent = str;
|
|
212
134
|
return temp.innerHTML;
|
|
213
135
|
}
|
|
214
136
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
this.container.className = 'vdt-player-osd';
|
|
227
|
-
|
|
228
|
-
// vertically center with css
|
|
229
|
-
this.container.innerHTML = `
|
|
230
|
-
<table>
|
|
231
|
-
<tbody>
|
|
232
|
-
<td>
|
|
233
|
-
<div class="osd-feedback-icon"></div>
|
|
234
|
-
</td>
|
|
235
|
-
</tbody>
|
|
236
|
-
</table>
|
|
237
|
-
`;
|
|
238
|
-
|
|
239
|
-
this.iconEl = this.container.getElementsByClassName('osd-feedback-icon')[0];
|
|
240
|
-
|
|
241
|
-
this.props.target && this.props.target.appendChild(this.container);
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
feedback(feedbackType, details = null) { // details - {} - can contain additional data
|
|
245
|
-
if (!this.state.enabled) {
|
|
246
|
-
return;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
let className;
|
|
250
|
-
|
|
251
|
-
switch (feedbackType) {
|
|
252
|
-
case constants$2.osd.pause:
|
|
253
|
-
className = 'pause';
|
|
254
|
-
break;
|
|
255
|
-
case constants$2.osd.play:
|
|
256
|
-
className = 'play';
|
|
257
|
-
break;
|
|
258
|
-
case constants$2.osd.volchange:
|
|
259
|
-
const currentVolumeLevel = details.volume;
|
|
260
|
-
let perceivedVolumeLevel; // 'low' | 'mid' | 'high' string to utilize video js eisting icons
|
|
261
|
-
|
|
262
|
-
/*
|
|
263
|
-
case switch will be too slow for this, if's are 2x more performant for this case
|
|
264
|
-
(Except in IE)
|
|
265
|
-
so... no case switch inside case switch this time :/
|
|
266
|
-
*/
|
|
267
|
-
|
|
268
|
-
// alues here are a bit of a guess, but they seem to match videojs thresholds
|
|
269
|
-
if (currentVolumeLevel === 0) { perceivedVolumeLevel = 'null'; } else
|
|
270
|
-
if (currentVolumeLevel > 0.65) { perceivedVolumeLevel = 'high'; } else
|
|
271
|
-
if (currentVolumeLevel < 0.35) { perceivedVolumeLevel = 'low'; } else { perceivedVolumeLevel = 'mid'; }
|
|
272
|
-
|
|
273
|
-
className = `volchange ${perceivedVolumeLevel}`;
|
|
274
|
-
break;
|
|
275
|
-
case constants$2.osd.jumpForward:
|
|
276
|
-
className = 'forward-jump';
|
|
277
|
-
break;
|
|
278
|
-
case constants$2.osd.jumpBackward:
|
|
279
|
-
className = 'backward-jump';
|
|
280
|
-
break;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
if (this.osdTimeout) { // should clear previous timeout/classname if in progress
|
|
285
|
-
this.container.classList.remove('active');
|
|
286
|
-
clearTimeout(this.osdTimeout);
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
// do feedback
|
|
290
|
-
this.container.classList.add('active');
|
|
291
|
-
this.osdTimeout = setTimeout(() => {
|
|
292
|
-
this.container.classList.remove('active');
|
|
293
|
-
}, 200);
|
|
294
|
-
|
|
295
|
-
// get specific with classnames
|
|
296
|
-
this.iconEl.className = `osd-feedback-icon ${className}`; // gets an overwrite each time
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
disable() {
|
|
300
|
-
this.state.enabled = false;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
enable() {
|
|
304
|
-
this.state.enabled = true;
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
/* eslint-disable no-restricted-globals */
|
|
309
|
-
/* eslint-disable class-methods-use-this */
|
|
310
|
-
/* eslint-disable no-plusplus */
|
|
311
|
-
/* eslint-disable no-unused-expressions */
|
|
312
|
-
|
|
313
|
-
const timeCodeNodeNames = [
|
|
314
|
-
'hours',
|
|
315
|
-
'minutes',
|
|
316
|
-
'seconds',
|
|
317
|
-
'frame',
|
|
318
|
-
];
|
|
319
|
-
|
|
320
|
-
class TimeCodeDisplay {// displays and renders smpte timecodes
|
|
137
|
+
const buttonNames = Object.freeze({
|
|
138
|
+
play: 'play-pause',
|
|
139
|
+
start: 'start',
|
|
140
|
+
fb: 'frame-backward',
|
|
141
|
+
ff: 'frame-forward',
|
|
142
|
+
end: 'end'
|
|
143
|
+
});
|
|
144
|
+
const buttons = [
|
|
145
|
+
buttonNames.start, buttonNames.fb, buttonNames.play, buttonNames.ff, buttonNames.end];
|
|
146
|
+
const CSS$2 = "\n .vdt-external-controls{\n display: flex;\n justify-content: center;\n align-items: center;\n }\n\n .control{\n flex: 1;\n flex-grow: 1;\n height: 100%;\n align-contents: center;\n align-self: center;\n text-align: center;\n vertical-align: middle;\n cursor: pointer;\n user-select: none;\n height: 20px;\n padding-top: 10px;\n padding-bottom: 10px;\n }\n\n .control .icon{\n display: inline-block;\n height: 20px;\n white-space: nowrap;\n opacity: .9;\n }\n\n .control:hover .icon{ opacity: 1; }\n\n .control .icon:before{\n opacity: 1;\n flex: 1;\n align-self: center;\n content: \" \";\n display: inline-block;\n margin: 0 auto;\n\n /* triangles */\n width: 0;\n height: 0;\n border-style: solid;\n border-width: 16px 0 16px 23px;\n border-color: transparent transparent transparent ".concat(colors.gray, ";\n }\n\n .vdt-external-controls.").concat(classNames.onDark, " .control .icon:before{\n border-color: transparent transparent transparent ").concat(colors.light, ";\n }\n\n /* specific buttons */\n\n .control.").concat(buttonNames.start, ",\n .control.").concat(buttonNames.end, "{\n height: 20px;\n }\n\n .control.").concat(buttonNames.play, "{\n height: 30px;\n padding-top: 0px;\n padding-bottom: 0px;\n }\n\n .control.").concat(buttonNames.play, " .icon{\n height: 30px;\n }\n\n .control.").concat(buttonNames.ff, " .icon:before,\n .control.").concat(buttonNames.fb, " .icon:before,\n .control.").concat(buttonNames.end, " .icon:before,\n .control.").concat(buttonNames.start, " .icon:before{\n border-width: 10px 0 10px 16px;\n }\n\n .control.").concat(buttonNames.fb, " .icon,\n .control.").concat(buttonNames.start, "{\n transform: rotate(180deg);\n }\n\n .control.").concat(buttonNames.end, " .icon:after,\n .control.").concat(buttonNames.start, " .icon:after{\n content: \" \";\n width: 4px;\n height: 20px;\n display: inline-block;\n background: ").concat(colors.gray, ";\n }\n\n .vdt-external-controls.").concat(classNames.onDark, " .control.").concat(buttonNames.end, " .icon:after,\n .vdt-external-controls.").concat(classNames.onDark, " .control.").concat(buttonNames.start, " .icon:after{\n background: ").concat(colors.light, ";\n }\n\n /* stateful styles */\n .control.").concat(buttonNames.play, ".playing .icon:before{\n height: 30px;\n width: 6px;\n border-width: 0px 8px 0px 8px;\n border-color: transparent ").concat(colors.gray, " transparent ").concat(colors.gray, ";\n }\n\n .vdt-external-controls.").concat(classNames.onDark, " .control.").concat(buttonNames.play, ".playing .icon:before{\n border-color: transparent ").concat(colors.light, " transparent ").concat(colors.light, ";\n }\n\n .vdt-external-controls.").concat(classNames.loading, " .control.").concat(buttonNames.play, "{\n border-color: transparent #f00 transparent #f00;\n }\n");
|
|
147
|
+
class ExternalControls {
|
|
321
148
|
constructor(props) {
|
|
322
149
|
this.props = props;
|
|
323
|
-
|
|
150
|
+
reactiveSetters.apply(this);
|
|
324
151
|
this.state = {
|
|
325
|
-
|
|
152
|
+
playing: false,
|
|
153
|
+
onDark: false,
|
|
154
|
+
loading: false
|
|
326
155
|
};
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
'vdt-timecode',
|
|
330
|
-
'vjs-time-control', // will apply default videojs style to the whole container, centers things vertically
|
|
331
|
-
(!(this.props.onInput)) ? 'duration' : '', // if no input capability, assume it's a duration timecode
|
|
332
|
-
];
|
|
156
|
+
this.shadowRoot = document.createElement('div');
|
|
157
|
+
this.shadowRoot.className = 'vdt-external-controls-wrapper';
|
|
333
158
|
this.container = document.createElement('div');
|
|
334
|
-
this.container.className =
|
|
335
|
-
|
|
336
|
-
this.nodeNames = [].concat(timeCodeNodeNames); // used internally
|
|
337
|
-
this.nodes = {}; // store sub-element nodes for mapped access here
|
|
338
|
-
|
|
339
|
-
this.nodeNames.forEach((nodeName, index) => {
|
|
340
|
-
const node = document.createElement('input');
|
|
341
|
-
node.className = nodeName;
|
|
342
|
-
node.tabIndex = -1; // prevent default Tab behaviour for cycling inputs
|
|
343
|
-
|
|
344
|
-
if (this.props.onInput) { // optional input capabilities
|
|
345
|
-
node.maxLength = 2;
|
|
346
|
-
|
|
347
|
-
node.onfocus = (e) => {
|
|
348
|
-
this.handleInputFocus(e, nodeName);
|
|
349
|
-
};
|
|
350
|
-
|
|
351
|
-
node.onblur = (e) => {
|
|
352
|
-
this.handleInputBlur(e, nodeName);
|
|
353
|
-
};
|
|
354
|
-
|
|
355
|
-
node.onmouseup = (e) => {
|
|
356
|
-
e.preventDefault();
|
|
357
|
-
e.currentTarget.select();
|
|
358
|
-
};
|
|
359
|
-
|
|
360
|
-
node.onkeydown = (e) => {
|
|
361
|
-
this.handleTimeCodeInput(e, nodeName);
|
|
362
|
-
};
|
|
363
|
-
|
|
364
|
-
node.onkeyup = (e) => {
|
|
365
|
-
this.handleTimeCodeInputOnKeyUp(e, nodeName);
|
|
366
|
-
};
|
|
367
|
-
} else {
|
|
368
|
-
node.readOnly = true; // display-only timecode
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
this.nodes[nodeName] = node;
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
const colon = document.createElement('span');
|
|
375
|
-
colon.innerHTML = ':';
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
this.container.appendChild(node);
|
|
379
|
-
(index !== this.nodeNames.length - 1) && this.container.appendChild(colon);
|
|
380
|
-
});
|
|
381
|
-
|
|
159
|
+
this.container.className = 'vdt-external-controls';
|
|
382
160
|
if (this.props.target) {
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
this.
|
|
391
|
-
|
|
392
|
-
// eslint-disable-next-line no-console
|
|
393
|
-
console.error(`Unable to instantiate a new ${this.constructor.name} without target DOM node`); // no joy
|
|
161
|
+
this.props.target.appendChild(this.shadowRoot);
|
|
162
|
+
this.shadow = this.shadowRoot.attachShadow({
|
|
163
|
+
mode: 'open'
|
|
164
|
+
});
|
|
165
|
+
this.style = document.createElement('style');
|
|
166
|
+
this.style.type = 'text/css';
|
|
167
|
+
this.style.appendChild(document.createTextNode(CSS$2));
|
|
168
|
+
this.shadow.appendChild(this.style);
|
|
169
|
+
this.shadow.appendChild(this.container);
|
|
394
170
|
}
|
|
171
|
+
this.handleNewProps(props);
|
|
172
|
+
this.bindEvents();
|
|
173
|
+
this.draw();
|
|
395
174
|
}
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
const
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
175
|
+
draw() {
|
|
176
|
+
this.buttons = {};
|
|
177
|
+
const excludes = this.props.excludes || [];
|
|
178
|
+
buttons.forEach(buttonName => {
|
|
179
|
+
if (excludes.indexOf(buttonName) < 0) {
|
|
180
|
+
const btn = document.createElement('div');
|
|
181
|
+
btn.className = "control ".concat(buttonName);
|
|
182
|
+
btn.innerHTML = '<span class="icon"></span>';
|
|
183
|
+
btn.onclick = () => {
|
|
184
|
+
this.handlePress(buttonName);
|
|
185
|
+
};
|
|
186
|
+
this.buttons[buttonName] = btn;
|
|
187
|
+
this.container.appendChild(btn);
|
|
406
188
|
}
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
reset() {
|
|
411
|
-
this.update({
|
|
412
|
-
hours: 0,
|
|
413
|
-
minutes: 0,
|
|
414
|
-
seconds: 0,
|
|
415
|
-
frame: 0,
|
|
416
189
|
});
|
|
417
190
|
}
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
return output;
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
toDigitPairStr(strValue) {
|
|
436
|
-
return (strValue.length < 2) ? `0${strValue}` : strValue;
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
handleTimeCodeInput(e, nodeName) {
|
|
440
|
-
const nodeIndex = this.nodeNames.indexOf(nodeName);
|
|
441
|
-
|
|
442
|
-
switch (e.code) {
|
|
443
|
-
case 'Enter': // do work before submitting input
|
|
444
|
-
this.checkAndNormalizeAllInputs();
|
|
445
|
-
|
|
446
|
-
this.props.onInput && this.props.onInput(e, nodeName, {
|
|
447
|
-
hours: this.hours,
|
|
448
|
-
minutes: this.minutes,
|
|
449
|
-
seconds: this.seconds,
|
|
450
|
-
frame: this.frame,
|
|
451
|
-
});
|
|
452
|
-
|
|
453
|
-
this[nodeName] = e.currentTarget.value;
|
|
454
|
-
e.currentTarget.blur(); // done
|
|
455
|
-
break;
|
|
456
|
-
case 'Tab': // custom tab behaviour
|
|
457
|
-
e.preventDefault();
|
|
458
|
-
|
|
459
|
-
// tab trough inputs in a loop fashion
|
|
460
|
-
if (!e.shiftKey) {
|
|
461
|
-
if ((nodeIndex + 1) <= (this.nodeNames.length - 1)) {
|
|
462
|
-
this.nodes[this.nodeNames[nodeIndex + 1]].focus(); // focus next
|
|
463
|
-
} else {
|
|
464
|
-
this.nodes[this.nodeNames[0]].focus(); // focus first
|
|
465
|
-
}
|
|
466
|
-
} else if ((nodeIndex - 1) >= 0) {
|
|
467
|
-
this.nodes[this.nodeNames[nodeIndex - 1]].focus(); // focus previous
|
|
468
|
-
} else {
|
|
469
|
-
this.nodes[this.nodeNames[this.nodeNames.length - 1]].focus(); // focus last
|
|
470
|
-
}
|
|
471
|
-
break;
|
|
191
|
+
bindEvents() {
|
|
192
|
+
if (this.props.player && this.props.player.videojs) {
|
|
193
|
+
const {
|
|
194
|
+
player
|
|
195
|
+
} = this.props;
|
|
196
|
+
player.videojs.on('play', () => {
|
|
197
|
+
this.playing = true;
|
|
198
|
+
});
|
|
199
|
+
player.videojs.on('pause', () => {
|
|
200
|
+
this.playing = false;
|
|
201
|
+
});
|
|
202
|
+
player.videojs.on('stop', () => {
|
|
203
|
+
this.playing = false;
|
|
204
|
+
});
|
|
472
205
|
}
|
|
473
206
|
}
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
207
|
+
handlePress(buttonName) {
|
|
208
|
+
if (this.props.player) {
|
|
209
|
+
const {
|
|
210
|
+
player
|
|
211
|
+
} = this.props;
|
|
212
|
+
if (player.osd) player.osd.disable();
|
|
213
|
+
switch (buttonName) {
|
|
214
|
+
case buttonNames.start:
|
|
215
|
+
player.toStart();
|
|
216
|
+
break;
|
|
217
|
+
case buttonNames.fb:
|
|
218
|
+
player.triggerHotkey('left');
|
|
219
|
+
break;
|
|
220
|
+
case buttonNames.play:
|
|
221
|
+
player.triggerHotkey('k');
|
|
222
|
+
break;
|
|
223
|
+
case buttonNames.ff:
|
|
224
|
+
player.triggerHotkey('right');
|
|
225
|
+
break;
|
|
226
|
+
case buttonNames.end:
|
|
227
|
+
player.toEnd();
|
|
228
|
+
break;
|
|
490
229
|
}
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
230
|
+
if (player.osd) player.osd.enable();
|
|
231
|
+
} else {
|
|
232
|
+
switch (buttonName) {
|
|
233
|
+
case buttonNames.start:
|
|
234
|
+
if (this.props.onPrev) this.props.onPrev();
|
|
235
|
+
break;
|
|
236
|
+
case buttonNames.fb:
|
|
237
|
+
if (this.props.onFB) this.props.onFB();
|
|
238
|
+
break;
|
|
239
|
+
case buttonNames.play:
|
|
240
|
+
if (this.playing) {
|
|
241
|
+
if (this.props.onPause) this.props.onPause();
|
|
242
|
+
} else if (this.props.onPlay) this.props.onPlay();
|
|
243
|
+
break;
|
|
244
|
+
case buttonNames.ff:
|
|
245
|
+
if (this.props.onFF) this.props.onFF();
|
|
246
|
+
break;
|
|
247
|
+
case buttonNames.end:
|
|
248
|
+
if (this.props.onNext) this.props.onNext();
|
|
249
|
+
break;
|
|
498
250
|
}
|
|
499
|
-
|
|
500
|
-
// make sure displayed timecode stays consistent after input and before time-based updates
|
|
501
|
-
this.nodes[nodeName].value = this.toDigitPairStr(this.sanitize(this.nodes[nodeName].value));
|
|
502
|
-
});
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
// setters and getters
|
|
506
|
-
|
|
507
|
-
set frame(val) {
|
|
508
|
-
this.nodes.frame.value = this.toDigitPairStr(val);
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
get frame() {
|
|
512
|
-
return parseInt(this.nodes.frame.value, 10);
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
set seconds(val) {
|
|
516
|
-
this.nodes.seconds.value = this.toDigitPairStr(val);
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
get seconds() {
|
|
520
|
-
return parseInt(this.nodes.seconds.value, 10);
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
set minutes(val) {
|
|
524
|
-
this.nodes.minutes.value = this.toDigitPairStr(val);
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
get minutes() {
|
|
528
|
-
return parseInt(this.nodes.minutes.value, 10);
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
set hours(val) {
|
|
532
|
-
this.nodes.hours.value = this.toDigitPairStr(val);
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
get hours() {
|
|
536
|
-
return parseInt(this.nodes.hours.value, 10);
|
|
251
|
+
}
|
|
537
252
|
}
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
253
|
+
set playing(bool) {
|
|
254
|
+
if (bool) {
|
|
255
|
+
this.state.playing = true;
|
|
256
|
+
this.buttons[buttonNames.play].classList.add('playing');
|
|
257
|
+
} else {
|
|
258
|
+
this.state.playing = false;
|
|
259
|
+
this.buttons[buttonNames.play].classList.remove('playing');
|
|
260
|
+
}
|
|
541
261
|
}
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
return {
|
|
545
|
-
hours: this.hours,
|
|
546
|
-
minutes: this.minutes,
|
|
547
|
-
seconds: this.seconds,
|
|
548
|
-
frame: this.frame,
|
|
549
|
-
};
|
|
262
|
+
get playing() {
|
|
263
|
+
return this.state.playing;
|
|
550
264
|
}
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
265
|
+
set onDark(bool) {
|
|
266
|
+
if (bool) {
|
|
267
|
+
this.state.onDark = true;
|
|
268
|
+
this.container.classList.add(classNames.onDark);
|
|
269
|
+
} else {
|
|
270
|
+
this.state.onDark = false;
|
|
271
|
+
this.container.classList.remove(classNames.onDark);
|
|
272
|
+
}
|
|
554
273
|
}
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
return `${this.getFormatted('hours')}:${this.getFormatted('minutes')}:${this.getFormatted('seconds')}:${this.getFormatted('frame')}`;
|
|
274
|
+
get onDark() {
|
|
275
|
+
return this.container.classList.contains(classNames.onDark);
|
|
558
276
|
}
|
|
559
|
-
|
|
560
|
-
set external(bool) {
|
|
277
|
+
set loading(bool) {
|
|
561
278
|
if (bool) {
|
|
562
|
-
this.
|
|
279
|
+
this.state.loading = true;
|
|
280
|
+
this.container.classList.add(classNames.loading);
|
|
563
281
|
} else {
|
|
564
|
-
this.
|
|
282
|
+
this.state.loading = false;
|
|
283
|
+
this.container.classList.remove(classNames.loading);
|
|
565
284
|
}
|
|
566
285
|
}
|
|
286
|
+
get loading() {
|
|
287
|
+
return this.state.loading;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
ExternalControls.buttonNames = buttonNames;
|
|
567
291
|
|
|
568
|
-
|
|
569
|
-
|
|
292
|
+
function _defineProperty(obj, key, value) {
|
|
293
|
+
if (key in obj) {
|
|
294
|
+
Object.defineProperty(obj, key, {
|
|
295
|
+
value: value,
|
|
296
|
+
enumerable: true,
|
|
297
|
+
configurable: true,
|
|
298
|
+
writable: true
|
|
299
|
+
});
|
|
300
|
+
} else {
|
|
301
|
+
obj[key] = value;
|
|
570
302
|
}
|
|
303
|
+
return obj;
|
|
571
304
|
}
|
|
572
305
|
|
|
573
|
-
/* eslint-disable no-plusplus */
|
|
574
|
-
|
|
575
306
|
class HelpOverlay {
|
|
576
307
|
constructor(props) {
|
|
577
308
|
this.props = props;
|
|
578
|
-
|
|
579
309
|
this.state = {
|
|
580
|
-
active: this.props.active || false
|
|
310
|
+
active: this.props.active || false
|
|
581
311
|
};
|
|
582
|
-
|
|
583
312
|
this.container = document.createElement('div');
|
|
584
313
|
this.container.className = 'vdt-help-overlay';
|
|
585
314
|
this.container.innerHTML = '';
|
|
586
315
|
this.container.onclick = () => {
|
|
587
316
|
this.hide();
|
|
588
317
|
};
|
|
589
|
-
|
|
590
|
-
this.props.target && this.props.target.appendChild(this.container);
|
|
591
|
-
|
|
318
|
+
if (this.props.target) this.props.target.appendChild(this.container);
|
|
592
319
|
this.draw();
|
|
593
320
|
}
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
const rows = [
|
|
598
|
-
['⎵', 'Play / Pause'],
|
|
599
|
-
['⇧', 'Increase volume '],
|
|
600
|
-
['⇩', 'Decrease volume'],
|
|
601
|
-
['⇨', 'Step frame forward'],
|
|
602
|
-
['⇦', 'Step frame backward'],
|
|
603
|
-
['M', 'Mute / Unmute'],
|
|
604
|
-
|
|
605
|
-
['J', 'Seek 10 seconds backward'],
|
|
606
|
-
['K', 'Play / Pause'],
|
|
607
|
-
['L', 'Seek 10 seconds forward'],
|
|
608
|
-
['C', 'Toggle subtitles'],
|
|
609
|
-
['N', 'Toggle settings menu'],
|
|
610
|
-
['H', 'Toggle this help overlay'],
|
|
611
|
-
];
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
// split the data for 2 columns
|
|
321
|
+
draw() {
|
|
322
|
+
let tableRowMarkup = '';
|
|
323
|
+
const rows = [['⎵', 'Play / Pause'], ['⇧', 'Increase volume '], ['⇩', 'Decrease volume'], ['⇨', 'Step frame forward'], ['⇦', 'Step frame backward'], ['M', 'Mute / Unmute'], ['J', 'Seek 10 seconds backward'], ['K', 'Play / Pause'], ['L', 'Seek 10 seconds forward'], ['C', 'Toggle subtitles'], ['N', 'Toggle settings menu'], ['H', 'Toggle this help overlay']];
|
|
615
324
|
const halfpointIndex = Math.round(rows.length / 2);
|
|
616
|
-
const columns = [
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
];
|
|
620
|
-
|
|
621
|
-
// table will niceley auto adjust td's according to length
|
|
622
|
-
for (let i = 0; i < halfpointIndex; i++) {
|
|
623
|
-
tableRowMarkup += `
|
|
624
|
-
<tr>
|
|
625
|
-
<td><div>${columns[0][i][0]}</div></td>
|
|
626
|
-
<td>- ${columns[0][i][1]}</td>
|
|
627
|
-
|
|
628
|
-
<td>${(columns[1][i]) ? `<div>${columns[1][i][0]}</div>` : ''}</td>
|
|
629
|
-
<td>${(columns[1][i]) ? `- ${columns[1][i][1]}` : ''}</td>
|
|
630
|
-
</tr>
|
|
631
|
-
`;
|
|
325
|
+
const columns = [rows.slice(0, halfpointIndex), rows.slice(halfpointIndex, rows.length)];
|
|
326
|
+
for (let i = 0; i < halfpointIndex; i += 1) {
|
|
327
|
+
tableRowMarkup += "\n <tr>\n <td><div>".concat(columns[0][i][0], "</div></td>\n <td>- ").concat(columns[0][i][1], "</td>\n\n <td>").concat(columns[1][i] ? "<div>".concat(columns[1][i][0], "</div>") : '', "</td>\n <td>").concat(columns[1][i] ? "- ".concat(columns[1][i][1]) : '', "</td>\n </tr>\n ");
|
|
632
328
|
}
|
|
633
|
-
|
|
634
|
-
/*
|
|
635
|
-
insert table row markup in the table;
|
|
636
|
-
note that there are two tables going
|
|
637
|
-
on here - one is for vertically centering the
|
|
638
|
-
content of help overlay (the other table)
|
|
639
|
-
*/
|
|
640
|
-
|
|
641
|
-
this.container.innerHTML = `
|
|
642
|
-
<table>
|
|
643
|
-
<tbody>
|
|
644
|
-
<tr>
|
|
645
|
-
<td class="vdt-help-contents">
|
|
646
|
-
<table><tbody>${tableRowMarkup}</tbody></table>
|
|
647
|
-
</td>
|
|
648
|
-
</tr>
|
|
649
|
-
</tbody>
|
|
650
|
-
</table>
|
|
651
|
-
`;
|
|
329
|
+
this.container.innerHTML = "\n <table>\n <tbody>\n <tr>\n <td class=\"vdt-help-contents\">\n <table><tbody>".concat(tableRowMarkup, "</tbody></table>\n </td>\n </tr>\n </tbody>\n </table>\n ");
|
|
652
330
|
}
|
|
653
|
-
|
|
654
331
|
show() {
|
|
655
332
|
if (!this.state.active) {
|
|
656
333
|
this.container.classList.add('active');
|
|
657
334
|
this.state.active = true;
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
this.props.onToggle
|
|
335
|
+
mousetrap__default["default"].bind('esc', () => {
|
|
336
|
+
this.hide();
|
|
337
|
+
});
|
|
338
|
+
if (this.props.onToggle) this.props.onToggle(true);
|
|
662
339
|
}
|
|
663
340
|
}
|
|
664
|
-
|
|
665
341
|
hide() {
|
|
666
342
|
if (this.state.active) {
|
|
667
343
|
this.container.classList.remove('active');
|
|
668
344
|
this.state.active = false;
|
|
669
|
-
|
|
670
345
|
mousetrap__default["default"].unbind('esc');
|
|
671
|
-
|
|
672
|
-
this.props.onToggle && this.props.onToggle(false);
|
|
346
|
+
if (this.props.onToggle) this.props.onToggle(false);
|
|
673
347
|
}
|
|
674
348
|
}
|
|
675
|
-
|
|
676
349
|
toggle() {
|
|
677
350
|
if (this.state.active) {
|
|
678
351
|
this.hide();
|
|
@@ -682,9 +355,8 @@
|
|
|
682
355
|
}
|
|
683
356
|
}
|
|
684
357
|
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
358
|
+
function ownKeys$1(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
359
|
+
function _objectSpread$1(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys$1(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys$1(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
|
|
688
360
|
const constants$1 = Object.freeze({
|
|
689
361
|
className: 'vdt-menu',
|
|
690
362
|
menuClassName: 'menu',
|
|
@@ -697,192 +369,50 @@
|
|
|
697
369
|
textColorDark: '#333',
|
|
698
370
|
textColorLight: 'rgba(255,255,255)',
|
|
699
371
|
bgColorLight: 'rgba(255,255,255,.2)',
|
|
700
|
-
bgColorSelected: 'rgba(255,255,255,.1)'
|
|
701
|
-
},
|
|
702
|
-
});
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
const CSS$2 = () => `
|
|
706
|
-
.${constants$1.menuClassName}{
|
|
707
|
-
position: relative;
|
|
708
|
-
height: 100%;
|
|
709
|
-
width: 200%;
|
|
710
|
-
// min-width: 200px;
|
|
711
|
-
right: 0px;
|
|
712
|
-
bottom: 0px;
|
|
713
|
-
background: ${constants$1.defaults.bgColor};
|
|
714
|
-
z-index: 1px;
|
|
715
|
-
transform: translate3d(100%, 0px, 0px);
|
|
716
|
-
transition: all 300ms ease-in-out;
|
|
717
|
-
box-shadow: 0px 0px 30px rgb;
|
|
718
|
-
-webkit-backdrop-filter: blur(10px);
|
|
719
|
-
overflow: hidden;
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
.${constants$1.menuClassName} .level-1{
|
|
723
|
-
float: left;
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
.${constants$1.menuClassName} div h3{
|
|
727
|
-
padding: 16px 24px;
|
|
728
|
-
font-size: 12px;
|
|
729
|
-
border-bottom: 1px solid ${constants$1.defaults.bgColorLight}
|
|
730
|
-
}
|
|
731
|
-
|
|
732
|
-
.${constants$1.menuClassName} .level-2 h3{
|
|
733
|
-
cursor: pointer;
|
|
734
|
-
position: relative;
|
|
735
|
-
}
|
|
736
|
-
.${constants$1.menuClassName} .level-2 h3:before{
|
|
737
|
-
content: '◂';
|
|
738
|
-
margin-left: -12px;
|
|
739
|
-
width: 12px;
|
|
740
|
-
display: inline-block;
|
|
741
|
-
position: absolute;
|
|
742
|
-
margin-top: -1px;
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
.${constants$1.menuClassName} .level-1,
|
|
746
|
-
.${constants$1.menuClassName} .level-2{
|
|
747
|
-
transform: translate3d(0px, 0px, 0px);
|
|
748
|
-
transition: all 300ms ease-in-out;
|
|
749
|
-
width: 50%;
|
|
750
|
-
height: 100%;
|
|
751
|
-
float: left;
|
|
752
|
-
}
|
|
753
|
-
|
|
754
|
-
.${constants$1.menuClassName}.sub-level .level-1,
|
|
755
|
-
.${constants$1.menuClassName}.sub-level .level-2{
|
|
756
|
-
transform: translate3d(-100%, 0px, 0px);
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
.${constants$1.menuClassName} table{
|
|
760
|
-
border-collapse: collapse;
|
|
761
|
-
width: 100%;
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
.${constants$1.menuClassName}.open{
|
|
765
|
-
transform: translate3d(0px, 0px, 0px);
|
|
766
|
-
}
|
|
767
|
-
|
|
768
|
-
.${constants$1.menuClassName} tr{
|
|
769
|
-
cursor: pointer;
|
|
770
|
-
height: 40px;
|
|
771
|
-
}
|
|
772
|
-
|
|
773
|
-
.${constants$1.menuClassName} tr.selected{
|
|
774
|
-
background: ${constants$1.defaults.bgColorSelected};
|
|
775
|
-
}
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
.${constants$1.menuClassName} tr td{
|
|
779
|
-
color: white;
|
|
780
|
-
font-size: 15px;
|
|
781
|
-
vertical-align: middle;
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
.${constants$1.menuClassName} tr:hover td{
|
|
786
|
-
color: white;
|
|
787
|
-
background: ${constants$1.defaults.bgColorLight};
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
.${constants$1.menuClassName} tr td.title{
|
|
791
|
-
padding-top: 12px;
|
|
792
|
-
padding-bottom: 12px;
|
|
793
|
-
font-weight: 300;
|
|
794
|
-
font-family: Helvetica, Arial, sans-serif;
|
|
795
|
-
}
|
|
796
|
-
|
|
797
|
-
.${constants$1.menuClassName} tr td.caret{
|
|
798
|
-
font-size: 12px;
|
|
799
|
-
}
|
|
800
|
-
|
|
801
|
-
.${constants$1.menuClassName} tr td:first-child{
|
|
802
|
-
padding-left: 24px;
|
|
803
|
-
}
|
|
804
|
-
|
|
805
|
-
.${constants$1.menuClassName} tr td:last-child{
|
|
806
|
-
padding-right: 16px;
|
|
807
|
-
}
|
|
808
|
-
|
|
809
|
-
.${constants$1.menuClassName} tr.has-items td:last-child{
|
|
810
|
-
text-align: right;
|
|
372
|
+
bgColorSelected: 'rgba(255,255,255,.1)'
|
|
811
373
|
}
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
font-size: 12px;
|
|
815
|
-
text-align: right;
|
|
816
|
-
color: ${constants$1.defaults.textColorLight};
|
|
817
|
-
}
|
|
818
|
-
`;
|
|
819
|
-
|
|
374
|
+
});
|
|
375
|
+
const CSS$1 = () => "\n .".concat(constants$1.menuClassName, "{\n position: relative;\n height: 100%;\n width: 200%;\n // min-width: 200px;\n right: 0px;\n bottom: 0px;\n background: ").concat(constants$1.defaults.bgColor, ";\n z-index: 1px;\n transform: translate3d(100%, 0px, 0px);\n transition: all 300ms ease-in-out;\n box-shadow: 0px 0px 30px rgb;\n -webkit-backdrop-filter: blur(10px);\n overflow: hidden;\n }\n\n .").concat(constants$1.menuClassName, " .level-1{\n float: left;\n }\n\n .").concat(constants$1.menuClassName, " div h3{\n padding: 16px 24px;\n font-size: 12px;\n border-bottom: 1px solid ").concat(constants$1.defaults.bgColorLight, "\n }\n\n .").concat(constants$1.menuClassName, " .level-2 h3{\n cursor: pointer;\n position: relative;\n }\n .").concat(constants$1.menuClassName, " .level-2 h3:before{\n content: '\u25C2';\n margin-left: -12px;\n width: 12px;\n display: inline-block;\n position: absolute;\n margin-top: -1px;\n }\n\n .").concat(constants$1.menuClassName, " .level-1,\n .").concat(constants$1.menuClassName, " .level-2{\n transform: translate3d(0px, 0px, 0px);\n transition: all 300ms ease-in-out;\n width: 50%;\n height: 100%;\n float: left;\n }\n\n .").concat(constants$1.menuClassName, ".sub-level .level-1,\n .").concat(constants$1.menuClassName, ".sub-level .level-2{\n transform: translate3d(-100%, 0px, 0px);\n }\n\n .").concat(constants$1.menuClassName, " table{\n border-collapse: collapse;\n width: 100%;\n }\n\n .").concat(constants$1.menuClassName, ".open{\n transform: translate3d(0px, 0px, 0px);\n }\n\n .").concat(constants$1.menuClassName, " tr{\n cursor: pointer;\n height: 40px;\n }\n\n .").concat(constants$1.menuClassName, " tr.selected{\n background: ").concat(constants$1.defaults.bgColorSelected, ";\n }\n\n\n .").concat(constants$1.menuClassName, " tr td{\n color: white;\n font-size: 15px;\n vertical-align: middle;\n }\n\n \n .").concat(constants$1.menuClassName, " tr:hover td{\n color: white;\n background: ").concat(constants$1.defaults.bgColorLight, ";\n }\n\n .").concat(constants$1.menuClassName, " tr td.title{\n padding-top: 12px;\n padding-bottom: 12px;\n font-weight: 300;\n font-family: Helvetica, Arial, sans-serif; \n }\n\n .").concat(constants$1.menuClassName, " tr td.caret{\n font-size: 12px;\n }\n\n .").concat(constants$1.menuClassName, " tr td:first-child{\n padding-left: 24px;\n }\n\n .").concat(constants$1.menuClassName, " tr td:last-child{\n padding-right: 16px;\n }\n\n .").concat(constants$1.menuClassName, " tr.has-items td:last-child{\n text-align: right;\n }\n\n .").concat(constants$1.menuClassName, " tr.has-items td.subtitle{\n font-size: 12px;\n text-align: right;\n color: ").concat(constants$1.defaults.textColorLight, ";\n }\n");
|
|
820
376
|
class MenuDisplayItem {
|
|
821
377
|
constructor(props) {
|
|
822
378
|
this.props = props;
|
|
823
|
-
|
|
824
|
-
const classNames = [
|
|
825
|
-
constants$1.menuItemClassName,
|
|
826
|
-
this.props.items && 'has-items',
|
|
827
|
-
this.props.selected && 'selected',
|
|
828
|
-
];
|
|
379
|
+
const classNames = [constants$1.menuItemClassName, this.props.items && 'has-items', this.props.selected && 'selected'];
|
|
829
380
|
this.container = document.createElement('tr');
|
|
830
381
|
this.container.className = classNames.join(' ');
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
// bind click
|
|
836
|
-
this.container.onclick = (event) => {
|
|
837
|
-
this.props.onClick && this.props.onClick(event);
|
|
382
|
+
if (this.props.target) this.props.target.appendChild(this.container);
|
|
383
|
+
this.container.onclick = event => {
|
|
384
|
+
if (this.props.onClick) this.props.onClick(event);
|
|
838
385
|
};
|
|
839
|
-
|
|
840
386
|
this.render();
|
|
841
387
|
}
|
|
842
|
-
|
|
843
388
|
render() {
|
|
844
|
-
if (this.props.items) {
|
|
845
|
-
this.container.innerHTML =
|
|
846
|
-
<td class="title"></td>
|
|
847
|
-
<td class="subtitle"></td>
|
|
848
|
-
<td class="caret">▷</td>
|
|
849
|
-
`;
|
|
389
|
+
if (this.props.items) {
|
|
390
|
+
this.container.innerHTML = "\n <td class=\"title\"></td>\n <td class=\"subtitle\"></td>\n <td class=\"caret\">\u25B7</td>\n ";
|
|
850
391
|
} else {
|
|
851
|
-
this.container.innerHTML =
|
|
852
|
-
<td class="title"></td>
|
|
853
|
-
`;
|
|
392
|
+
this.container.innerHTML = "\n <td class=\"title\"></td>\n ";
|
|
854
393
|
}
|
|
855
|
-
|
|
856
394
|
const titleNode = this.container.getElementsByClassName('title')[0];
|
|
857
|
-
const subtitleNode =
|
|
858
|
-
|
|
395
|
+
const subtitleNode = this.props.items ? this.container.getElementsByClassName('subtitle')[0] : false;
|
|
859
396
|
titleNode.textContent = this.props.title;
|
|
860
|
-
|
|
397
|
+
if (subtitleNode) subtitleNode.textContent = this.props.subtitle;
|
|
861
398
|
}
|
|
862
399
|
}
|
|
863
|
-
|
|
864
400
|
class Menu {
|
|
865
401
|
constructor(props) {
|
|
866
402
|
this.props = props;
|
|
867
|
-
|
|
868
403
|
this.container = document.createElement('div');
|
|
869
|
-
this.container.className =
|
|
870
|
-
|
|
404
|
+
this.container.className = "".concat(constants$1.className);
|
|
871
405
|
this.state = {
|
|
872
406
|
opened: false,
|
|
873
407
|
selectedItem: 0,
|
|
874
408
|
items: [],
|
|
875
|
-
subItems: []
|
|
409
|
+
subItems: []
|
|
876
410
|
};
|
|
877
|
-
|
|
878
411
|
this.mount();
|
|
879
412
|
this.draw();
|
|
880
413
|
}
|
|
881
|
-
|
|
882
414
|
mount() {
|
|
883
|
-
// this.props.target && this.props.target.appendChild(this.container)
|
|
884
415
|
if (this.props.target) {
|
|
885
|
-
// container node, acts as an overlay in is stylable from outside
|
|
886
416
|
this.container.style.position = 'absolute';
|
|
887
417
|
this.container.style.bottom = this.container.style.right = '0px';
|
|
888
418
|
this.container.style.height = '100%';
|
|
@@ -890,69 +420,53 @@
|
|
|
890
420
|
this.container.style.width = '30%';
|
|
891
421
|
this.container.style.minWidth = '250px';
|
|
892
422
|
this.container.style.maxWidth = '320px';
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
this.props.target
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
// node for menu itself
|
|
423
|
+
this.shadow = this.container.attachShadow({
|
|
424
|
+
mode: 'open'
|
|
425
|
+
});
|
|
426
|
+
if (this.props.target) this.props.target.appendChild(this.container);
|
|
900
427
|
this.menuContainer = document.createElement('div');
|
|
901
428
|
this.menuContainer.className = 'menu';
|
|
902
|
-
|
|
903
429
|
this.shadow.appendChild(this.menuContainer);
|
|
904
|
-
|
|
905
|
-
// attach styles
|
|
906
430
|
this.style = document.createElement('style');
|
|
907
431
|
this.style.type = 'text/css';
|
|
908
|
-
this.style.innerHTML = CSS$
|
|
432
|
+
this.style.innerHTML = CSS$1();
|
|
909
433
|
this.shadow.appendChild(this.style);
|
|
910
434
|
}
|
|
911
435
|
}
|
|
912
|
-
|
|
913
|
-
draw() { // first draw
|
|
436
|
+
draw() {
|
|
914
437
|
const mainDiv = document.createElement('div');
|
|
915
438
|
mainDiv.className = 'level-1';
|
|
916
439
|
this.mainLevel = document.createElement('table');
|
|
917
440
|
mainDiv.innerHTML = '<h3>Settings</h3>';
|
|
918
441
|
mainDiv.appendChild(this.mainLevel);
|
|
919
|
-
|
|
920
442
|
const subDiv = document.createElement('div');
|
|
921
443
|
subDiv.className = 'level-2';
|
|
922
444
|
this.subLvlTitle = document.createElement('h3');
|
|
923
|
-
this.subLvlTitle.onclick = () => {
|
|
445
|
+
this.subLvlTitle.onclick = () => {
|
|
446
|
+
this.up();
|
|
447
|
+
};
|
|
924
448
|
subDiv.appendChild(this.subLvlTitle);
|
|
925
449
|
this.secondaryLevel = document.createElement('table');
|
|
926
450
|
subDiv.appendChild(this.secondaryLevel);
|
|
927
|
-
|
|
928
|
-
|
|
929
451
|
this.menuContainer.appendChild(mainDiv);
|
|
930
452
|
this.menuContainer.appendChild(subDiv);
|
|
931
|
-
|
|
932
|
-
this.props.items.forEach((menuItem) => {
|
|
933
|
-
// get selected item title if such exists
|
|
453
|
+
this.props.items.forEach(menuItem => {
|
|
934
454
|
const activeTitle = menuItem.items[menuItem.getActiveIndex(menuItem.items)].title || '';
|
|
935
|
-
const displayItem = new MenuDisplayItem({
|
|
455
|
+
const displayItem = new MenuDisplayItem(_objectSpread$1({
|
|
936
456
|
target: this.mainLevel,
|
|
937
457
|
subtitle: activeTitle,
|
|
938
458
|
onClick: () => {
|
|
939
459
|
this.handleSupItemSelected(menuItem);
|
|
940
|
-
}
|
|
941
|
-
|
|
942
|
-
});
|
|
943
|
-
|
|
460
|
+
}
|
|
461
|
+
}, menuItem));
|
|
944
462
|
this.state.items.push(displayItem);
|
|
945
463
|
});
|
|
946
464
|
}
|
|
947
|
-
|
|
948
465
|
open() {
|
|
949
466
|
this.render();
|
|
950
|
-
|
|
951
467
|
this.menuContainer.classList.add('open');
|
|
952
|
-
this.props.onOpen
|
|
468
|
+
if (this.props.onOpen) this.props.onOpen();
|
|
953
469
|
this.state.opened = true;
|
|
954
|
-
|
|
955
|
-
// close the menu when user clicks outside it
|
|
956
470
|
if (!this.handleClicksWhenMenuOpened) {
|
|
957
471
|
this.handleClicksWhenMenuOpened = function (event) {
|
|
958
472
|
if (this.state.opened) {
|
|
@@ -964,25 +478,19 @@
|
|
|
964
478
|
}
|
|
965
479
|
}.bind(this);
|
|
966
480
|
}
|
|
967
|
-
|
|
968
481
|
this.handleClicksWhenMenuOpenedTimeout = setTimeout(() => {
|
|
969
482
|
document.addEventListener('click', this.handleClicksWhenMenuOpened);
|
|
970
|
-
mousetrap__default["default"].bind('esc', this.close.bind(this));
|
|
483
|
+
mousetrap__default["default"].bind('esc', this.close.bind(this));
|
|
971
484
|
}, constants$1.animationLength);
|
|
972
485
|
}
|
|
973
|
-
|
|
974
486
|
close() {
|
|
975
487
|
this.menuContainer.classList.remove('open');
|
|
976
488
|
this.state.opened = false;
|
|
977
|
-
|
|
978
|
-
this.handleClicksWhenMenuOpenedTimeout && clearTimeout(this.handleClicksWhenMenuOpenedTimeout);
|
|
489
|
+
if (this.handleClicksWhenMenuOpenedTimeout) clearTimeout(this.handleClicksWhenMenuOpenedTimeout);
|
|
979
490
|
document.removeEventListener('click', this.handleClicksWhenMenuOpened);
|
|
980
|
-
|
|
981
|
-
this.props.onClose && this.props.onClose();
|
|
982
|
-
|
|
491
|
+
if (this.props.onClose) this.props.onClose();
|
|
983
492
|
mousetrap__default["default"].unbind('esc');
|
|
984
493
|
}
|
|
985
|
-
|
|
986
494
|
toggle() {
|
|
987
495
|
if (this.state.opened) {
|
|
988
496
|
this.close();
|
|
@@ -990,56 +498,48 @@
|
|
|
990
498
|
this.open();
|
|
991
499
|
}
|
|
992
500
|
}
|
|
993
|
-
|
|
994
|
-
up() { // go to level 1
|
|
501
|
+
up() {
|
|
995
502
|
this.menuContainer.classList.remove(constants$1.subLvlClassName);
|
|
996
503
|
this.render();
|
|
997
504
|
}
|
|
998
|
-
|
|
999
505
|
handleSupItemSelected(item) {
|
|
1000
506
|
this.subLvlTitle.textContent = item.title;
|
|
1001
507
|
this.renderSubItems(item.items, item.getActiveIndex(item.items));
|
|
1002
508
|
this.menuContainer.classList.add(constants$1.subLvlClassName);
|
|
1003
509
|
}
|
|
1004
|
-
|
|
1005
|
-
|
|
510
|
+
renderSubItems(items) {
|
|
511
|
+
let activeIndex = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
1006
512
|
this.secondaryLevel.innerHTML = '';
|
|
1007
|
-
|
|
1008
513
|
const subItemRefs = [];
|
|
1009
514
|
items.forEach((menuItem, index) => {
|
|
1010
|
-
const displayItem = new MenuDisplayItem({
|
|
1011
|
-
target: this.secondaryLevel
|
|
1012
|
-
|
|
1013
|
-
onClick:
|
|
515
|
+
const displayItem = new MenuDisplayItem(_objectSpread$1(_objectSpread$1({
|
|
516
|
+
target: this.secondaryLevel
|
|
517
|
+
}, menuItem), {}, {
|
|
518
|
+
onClick: event => {
|
|
1014
519
|
this.handleSubItemSelected(event, menuItem);
|
|
1015
520
|
},
|
|
1016
|
-
selected:
|
|
1017
|
-
});
|
|
1018
|
-
|
|
521
|
+
selected: index === activeIndex
|
|
522
|
+
}));
|
|
1019
523
|
subItemRefs.push(displayItem);
|
|
1020
524
|
});
|
|
1021
|
-
|
|
1022
525
|
this.state.subItems = subItemRefs;
|
|
1023
526
|
}
|
|
1024
|
-
|
|
1025
527
|
handleSubItemSelected(event, item) {
|
|
1026
528
|
this.close();
|
|
1027
|
-
item.onClick
|
|
529
|
+
if (item.onClick) item.onClick(event, item);
|
|
1028
530
|
this.up();
|
|
1029
531
|
}
|
|
1030
|
-
|
|
1031
532
|
get opened() {
|
|
1032
533
|
return this.state.opened;
|
|
1033
534
|
}
|
|
1034
|
-
|
|
1035
535
|
set opened(bool) {
|
|
1036
536
|
this.state.opened = bool;
|
|
1037
537
|
}
|
|
1038
|
-
|
|
1039
538
|
render() {
|
|
1040
|
-
// update selections at level 1
|
|
1041
539
|
this.state.items.forEach((menuDisplayItem, index) => {
|
|
1042
|
-
const {
|
|
540
|
+
const {
|
|
541
|
+
items
|
|
542
|
+
} = this.props;
|
|
1043
543
|
const activeIndex = items[index].getActiveIndex(items[index].items);
|
|
1044
544
|
const activeTitle = items[index].items[activeIndex].title;
|
|
1045
545
|
menuDisplayItem.props.subtitle = activeTitle;
|
|
@@ -1048,224 +548,86 @@
|
|
|
1048
548
|
}
|
|
1049
549
|
}
|
|
1050
550
|
|
|
1051
|
-
|
|
551
|
+
class OSD {
|
|
552
|
+
constructor(props) {
|
|
553
|
+
this.props = props;
|
|
554
|
+
this.state = {
|
|
555
|
+
enabled: true
|
|
556
|
+
};
|
|
557
|
+
this.container = document.createElement('div');
|
|
558
|
+
this.container.className = 'vdt-player-osd';
|
|
559
|
+
this.container.innerHTML = "\n <table>\n <tbody>\n <td>\n <div class=\"osd-feedback-icon\"></div>\n </td>\n </tbody>\n </table>\n ";
|
|
560
|
+
this.iconEl = this.container.getElementsByClassName('osd-feedback-icon')[0];
|
|
561
|
+
if (this.props.target) this.props.target.appendChild(this.container);
|
|
562
|
+
}
|
|
563
|
+
feedback(feedbackType) {
|
|
564
|
+
let details = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
565
|
+
if (!this.state.enabled) {
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
let className;
|
|
569
|
+
switch (feedbackType) {
|
|
570
|
+
case osd.pause:
|
|
571
|
+
className = 'pause';
|
|
572
|
+
break;
|
|
573
|
+
case osd.play:
|
|
574
|
+
className = 'play';
|
|
575
|
+
break;
|
|
576
|
+
case osd.volchange:
|
|
577
|
+
const currentVolumeLevel = details.volume;
|
|
578
|
+
let perceivedVolumeLevel;
|
|
579
|
+
if (currentVolumeLevel === 0) {
|
|
580
|
+
perceivedVolumeLevel = 'null';
|
|
581
|
+
} else if (currentVolumeLevel > 0.65) {
|
|
582
|
+
perceivedVolumeLevel = 'high';
|
|
583
|
+
} else if (currentVolumeLevel < 0.35) {
|
|
584
|
+
perceivedVolumeLevel = 'low';
|
|
585
|
+
} else {
|
|
586
|
+
perceivedVolumeLevel = 'mid';
|
|
587
|
+
}
|
|
588
|
+
className = "volchange ".concat(perceivedVolumeLevel);
|
|
589
|
+
break;
|
|
590
|
+
case osd.jumpForward:
|
|
591
|
+
className = 'forward-jump';
|
|
592
|
+
break;
|
|
593
|
+
case osd.jumpBackward:
|
|
594
|
+
className = 'backward-jump';
|
|
595
|
+
break;
|
|
596
|
+
}
|
|
597
|
+
if (this.osdTimeout) {
|
|
598
|
+
this.container.classList.remove('active');
|
|
599
|
+
clearTimeout(this.osdTimeout);
|
|
600
|
+
}
|
|
601
|
+
this.container.classList.add('active');
|
|
602
|
+
this.osdTimeout = setTimeout(() => {
|
|
603
|
+
this.container.classList.remove('active');
|
|
604
|
+
}, 200);
|
|
605
|
+
this.iconEl.className = "osd-feedback-icon ".concat(className);
|
|
606
|
+
}
|
|
607
|
+
disable() {
|
|
608
|
+
this.state.enabled = false;
|
|
609
|
+
}
|
|
610
|
+
enable() {
|
|
611
|
+
this.state.enabled = true;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
1052
614
|
|
|
1053
615
|
const constants = Object.freeze({
|
|
1054
616
|
className: 'vdt-seekbar',
|
|
1055
617
|
defaults: {
|
|
1056
618
|
bgColor: '#fafafa',
|
|
1057
619
|
fillColor: '#f00',
|
|
1058
|
-
regionColor: '#f6e58d',
|
|
620
|
+
regionColor: '#f6e58d',
|
|
1059
621
|
markerWidth: 16,
|
|
1060
622
|
regionAccentColor: '#00a8ff',
|
|
1061
|
-
transitionTime: 300
|
|
623
|
+
transitionTime: 300
|
|
1062
624
|
},
|
|
1063
625
|
markerTypes: {
|
|
1064
626
|
in: 'in',
|
|
1065
|
-
out: 'out'
|
|
1066
|
-
}
|
|
627
|
+
out: 'out'
|
|
628
|
+
}
|
|
1067
629
|
});
|
|
1068
|
-
|
|
1069
|
-
const CSS$1 = (bgColor, fillColor) => `
|
|
1070
|
-
.${constants.className}{
|
|
1071
|
-
user-select: none;
|
|
1072
|
-
background: ${colors.light};
|
|
1073
|
-
height: 6px;
|
|
1074
|
-
width: 100%;
|
|
1075
|
-
position: relative;
|
|
1076
|
-
cursor: pointer;
|
|
1077
|
-
z-index: 5;
|
|
1078
|
-
}
|
|
1079
|
-
|
|
1080
|
-
.${classNames.onDark}.${constants.className}{
|
|
1081
|
-
background: ${colors.gray};
|
|
1082
|
-
}
|
|
1083
|
-
|
|
1084
|
-
.fill, .load-indicator{
|
|
1085
|
-
height: 100%;
|
|
1086
|
-
display: inline-block;
|
|
1087
|
-
position: absolute;
|
|
1088
|
-
left: 0px;
|
|
1089
|
-
top: 0px;
|
|
1090
|
-
background: ${fillColor};
|
|
1091
|
-
transition: width ${constants.defaults.transitionTime}ms linear;
|
|
1092
|
-
z-index: 2;
|
|
1093
|
-
}
|
|
1094
|
-
|
|
1095
|
-
.load-indicator{
|
|
1096
|
-
background: #e1e1e1;
|
|
1097
|
-
z-index: 1;
|
|
1098
|
-
opacity: .2;
|
|
1099
|
-
transition: none;
|
|
1100
|
-
}
|
|
1101
|
-
|
|
1102
|
-
.${classNames.onDark}.${constants.className} .load-indicator{
|
|
1103
|
-
background: white;
|
|
1104
|
-
}
|
|
1105
|
-
|
|
1106
|
-
.${constants.className}.dragging .fill{
|
|
1107
|
-
transition: none;
|
|
1108
|
-
}
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
.marker, .region{
|
|
1112
|
-
position: absolute;
|
|
1113
|
-
top: 0px;
|
|
1114
|
-
height: 100%;
|
|
1115
|
-
background: cyan;
|
|
1116
|
-
width: 1px;
|
|
1117
|
-
display: inline-block;
|
|
1118
|
-
z-index: 4;
|
|
1119
|
-
}
|
|
1120
|
-
|
|
1121
|
-
.marker{
|
|
1122
|
-
transition: opacity ${constants.defaults.transitionTime}ms linear;
|
|
1123
|
-
}
|
|
1124
|
-
|
|
1125
|
-
.marker{ display: none; }
|
|
1126
|
-
.marker.active{ display: initial; }
|
|
1127
|
-
|
|
1128
|
-
.marker .handle{
|
|
1129
|
-
position: absolute;
|
|
1130
|
-
bottom: 10px; right: 0px;
|
|
1131
|
-
width: ${constants.defaults.markerWidth}px;
|
|
1132
|
-
height: 28px;
|
|
1133
|
-
background: #999;
|
|
1134
|
-
border-radius: 3px;
|
|
1135
|
-
cursor: col-resize;
|
|
1136
|
-
z-index: 3;
|
|
1137
|
-
box-sizing: border-box;
|
|
1138
|
-
}
|
|
1139
|
-
|
|
1140
|
-
.marker.regional .handle{
|
|
1141
|
-
background: ${constants.defaults.regionAccentColor};
|
|
1142
|
-
box-shadow: -2px 1px 1px rgba(0,0,0,.1);
|
|
1143
|
-
}
|
|
1144
|
-
|
|
1145
|
-
.marker.regional.in .handle{
|
|
1146
|
-
box-shadow: 2px 1px 1px rgba(0,0,0,.1);
|
|
1147
|
-
}
|
|
1148
|
-
|
|
1149
|
-
.marker.in .handle{
|
|
1150
|
-
border-bottom-left-radius: 40px;
|
|
1151
|
-
}
|
|
1152
|
-
|
|
1153
|
-
.marker.out .handle{
|
|
1154
|
-
left: 1px;
|
|
1155
|
-
right: initial;
|
|
1156
|
-
border-bottom-right-radius: 20px;
|
|
1157
|
-
}
|
|
1158
|
-
|
|
1159
|
-
.handle:active{
|
|
1160
|
-
background: ${constants.defaults.regionColor};
|
|
1161
|
-
}
|
|
1162
|
-
|
|
1163
|
-
.region{
|
|
1164
|
-
position: absolute;
|
|
1165
|
-
width: auto;
|
|
1166
|
-
background: ${constants.defaults.regionColor};
|
|
1167
|
-
opacity: .7;
|
|
1168
|
-
}
|
|
1169
|
-
|
|
1170
|
-
.region.nav{
|
|
1171
|
-
background: transparent;
|
|
1172
|
-
opacity: 1;
|
|
1173
|
-
border-left: 1px solid cyan;
|
|
1174
|
-
}
|
|
1175
|
-
|
|
1176
|
-
.region.nav .bubble,
|
|
1177
|
-
.region.nav:after{
|
|
1178
|
-
content: " ";
|
|
1179
|
-
height: 16px;
|
|
1180
|
-
bottom: 10px;
|
|
1181
|
-
width: 16px;
|
|
1182
|
-
border-radius: 16px;
|
|
1183
|
-
background: ${constants.defaults.regionAccentColor};
|
|
1184
|
-
position: absolute;
|
|
1185
|
-
margin-left: -8px;
|
|
1186
|
-
transition: transform 200ms ease-out;
|
|
1187
|
-
transform: translate3d(0px, 0px, 0px);
|
|
1188
|
-
transform-origin: bottom center;
|
|
1189
|
-
}
|
|
1190
|
-
|
|
1191
|
-
.region.nav .popout{
|
|
1192
|
-
width: 160px;
|
|
1193
|
-
z-index: 4;
|
|
1194
|
-
background: rgba(28, 28, 28, .7);
|
|
1195
|
-
color: white;
|
|
1196
|
-
font-size: 14px;
|
|
1197
|
-
min-height: 100px;
|
|
1198
|
-
bottom: 16px;
|
|
1199
|
-
left: -80px;
|
|
1200
|
-
position: absolute;
|
|
1201
|
-
border-radius: 8px;
|
|
1202
|
-
-webkit-backdrop-filter: blur(10px);
|
|
1203
|
-
font-family: Arial, Helvetica, sans-serif;
|
|
1204
|
-
overflow: hidden;
|
|
1205
|
-
opacity: 0;
|
|
1206
|
-
visibility: hidden;
|
|
1207
|
-
}
|
|
1208
|
-
|
|
1209
|
-
.region.nav.right-aligned .popout{
|
|
1210
|
-
right: 0px;
|
|
1211
|
-
left: initial;
|
|
1212
|
-
}
|
|
1213
|
-
|
|
1214
|
-
.region.nav.left-aligned .popout{
|
|
1215
|
-
left: -32px;
|
|
1216
|
-
}
|
|
1217
|
-
|
|
1218
|
-
.region.nav .popout .title{
|
|
1219
|
-
padding: 4px 14px;
|
|
1220
|
-
text-align: center;
|
|
1221
|
-
color: black;
|
|
1222
|
-
background: white;
|
|
1223
|
-
}
|
|
1224
|
-
|
|
1225
|
-
.region.nav .popout .annotation{
|
|
1226
|
-
padding: 8px 12px;
|
|
1227
|
-
font-weight: light;
|
|
1228
|
-
color: rgba(255,255,255,.9);
|
|
1229
|
-
}
|
|
1230
|
-
|
|
1231
|
-
.region.nav:after{
|
|
1232
|
-
width: 1px;
|
|
1233
|
-
left: 8px;
|
|
1234
|
-
height: 10px;
|
|
1235
|
-
bottom: 0px;
|
|
1236
|
-
background: #00a8ff;
|
|
1237
|
-
}
|
|
1238
|
-
|
|
1239
|
-
.region.nav:hover{
|
|
1240
|
-
background: rgba(28, 28, 28, .5);
|
|
1241
|
-
}
|
|
1242
|
-
|
|
1243
|
-
.region.nav.has-popout:hover .bubble{
|
|
1244
|
-
background: rgba(28, 28, 28, .8);
|
|
1245
|
-
opacity: 1;
|
|
1246
|
-
z-index: 3;
|
|
1247
|
-
}
|
|
1248
|
-
|
|
1249
|
-
.region.nav:hover:after,
|
|
1250
|
-
.region.nav:hover:before{
|
|
1251
|
-
background: rgba(28, 28, 28, .8);
|
|
1252
|
-
}
|
|
1253
|
-
|
|
1254
|
-
.region.nav:hover .popout{
|
|
1255
|
-
opacity: 1;
|
|
1256
|
-
visibility: visible;
|
|
1257
|
-
}
|
|
1258
|
-
|
|
1259
|
-
.${constants.className}.dragging .bubble{
|
|
1260
|
-
transform: scale3d(.75,.75,.75);
|
|
1261
|
-
}
|
|
1262
|
-
|
|
1263
|
-
.${constants.className}.hide-markers .marker{
|
|
1264
|
-
opacity: 0;
|
|
1265
|
-
}
|
|
1266
|
-
|
|
1267
|
-
`;
|
|
1268
|
-
|
|
630
|
+
const CSS = (bgColor, fillColor) => "\n .".concat(constants.className, "{\n user-select: none;\n background: ").concat(colors.light, ";\n height: 6px;\n width: 100%;\n position: relative;\n cursor: pointer;\n z-index: 5;\n }\n\n .").concat(classNames.onDark, ".").concat(constants.className, "{\n background: ").concat(colors.gray, ";\n }\n\n .fill, .load-indicator{\n height: 100%;\n display: inline-block;\n position: absolute;\n left: 0px;\n top: 0px;\n background: ").concat(fillColor, ";\n transition: width ").concat(constants.defaults.transitionTime, "ms linear;\n z-index: 2;\n }\n\n .load-indicator{\n background: #e1e1e1;\n z-index: 1;\n opacity: .2;\n transition: none;\n }\n\n .").concat(classNames.onDark, ".").concat(constants.className, " .load-indicator{\n background: white;\n }\n\n .").concat(constants.className, ".dragging .fill{\n transition: none;\n }\n\n\n .marker, .region{\n position: absolute;\n top: 0px;\n height: 100%;\n background: cyan;\n width: 1px;\n display: inline-block;\n z-index: 4;\n }\n\n .marker{\n transition: opacity ").concat(constants.defaults.transitionTime, "ms linear;\n }\n\n .marker{ display: none; }\n .marker.active{ display: initial; }\n\n .marker .handle{\n position: absolute;\n bottom: 10px; right: 0px;\n width: ").concat(constants.defaults.markerWidth, "px;\n height: 28px;\n background: #999;\n border-radius: 3px;\n cursor: col-resize;\n z-index: 3;\n box-sizing: border-box;\n }\n\n .marker.regional .handle{\n background: ").concat(constants.defaults.regionAccentColor, ";\n box-shadow: -2px 1px 1px rgba(0,0,0,.1);\n }\n\n .marker.regional.in .handle{\n box-shadow: 2px 1px 1px rgba(0,0,0,.1);\n }\n\n .marker.in .handle{\n border-bottom-left-radius: 40px;\n }\n\n .marker.out .handle{\n left: 1px;\n right: initial;\n border-bottom-right-radius: 20px;\n }\n\n .handle:active{\n background: ").concat(constants.defaults.regionColor, ";\n }\n\n .region{\n position: absolute;\n width: auto;\n background: ").concat(constants.defaults.regionColor, ";\n opacity: .7;\n }\n\n .region.nav{\n background: transparent;\n opacity: 1;\n border-left: 1px solid cyan;\n }\n\n .region.nav .bubble,\n .region.nav:after{\n content: \" \";\n height: 16px;\n bottom: 10px;\n width: 16px;\n border-radius: 16px;\n background: ").concat(constants.defaults.regionAccentColor, ";\n position: absolute;\n margin-left: -8px;\n transition: transform 200ms ease-out;\n transform: translate3d(0px, 0px, 0px);\n transform-origin: bottom center;\n }\n\n .region.nav .popout{\n width: 160px;\n z-index: 4;\n background: rgba(28, 28, 28, .7);\n color: white;\n font-size: 14px;\n min-height: 100px;\n bottom: 16px;\n left: -80px;\n position: absolute;\n border-radius: 8px;\n -webkit-backdrop-filter: blur(10px);\n font-family: Arial, Helvetica, sans-serif;\n overflow: hidden;\n opacity: 0;\n visibility: hidden;\n }\n\n .region.nav.right-aligned .popout{\n right: 0px;\n left: initial;\n }\n\n .region.nav.left-aligned .popout{\n left: -32px;\n } \n\n .region.nav .popout .title{\n padding: 4px 14px;\n text-align: center;\n color: black;\n background: white;\n }\n\n .region.nav .popout .annotation{\n padding: 8px 12px;\n font-weight: light;\n color: rgba(255,255,255,.9);\n }\n\n .region.nav:after{\n width: 1px;\n left: 8px;\n height: 10px;\n bottom: 0px;\n background: #00a8ff;\n }\n\n .region.nav:hover{\n background: rgba(28, 28, 28, .5);\n }\n\n .region.nav.has-popout:hover .bubble{\n background: rgba(28, 28, 28, .8);\n opacity: 1;\n z-index: 3;\n }\n\n .region.nav:hover:after,\n .region.nav:hover:before{\n background: rgba(28, 28, 28, .8);\n }\n\n .region.nav:hover .popout{\n opacity: 1;\n visibility: visible;\n }\n\n .").concat(constants.className, ".dragging .bubble{\n transform: scale3d(.75,.75,.75);\n }\n\n .").concat(constants.className, ".hide-markers .marker{\n opacity: 0;\n }\n\n");
|
|
1269
631
|
class Region {
|
|
1270
632
|
constructor(props) {
|
|
1271
633
|
const regionDefaultProps = {
|
|
@@ -1273,373 +635,273 @@
|
|
|
1273
635
|
out: null,
|
|
1274
636
|
title: '',
|
|
1275
637
|
annotation: '',
|
|
1276
|
-
el: null
|
|
638
|
+
el: null
|
|
1277
639
|
};
|
|
1278
|
-
|
|
1279
|
-
Object.assign(this, regionDefaultProps, props); // apply props
|
|
640
|
+
Object.assign(this, regionDefaultProps, props);
|
|
1280
641
|
}
|
|
1281
642
|
}
|
|
1282
|
-
|
|
1283
643
|
class SeekBar {
|
|
1284
644
|
constructor(props) {
|
|
1285
645
|
this.props = props;
|
|
1286
|
-
reactiveSetters.apply(this);
|
|
1287
|
-
|
|
646
|
+
reactiveSetters.apply(this);
|
|
1288
647
|
this.container = document.createElement('div');
|
|
1289
|
-
this.container.className =
|
|
1290
|
-
|
|
648
|
+
this.container.className = "".concat(constants.className, "-wrapper");
|
|
1291
649
|
this.state = {
|
|
1292
|
-
in: null,
|
|
650
|
+
in: null,
|
|
1293
651
|
out: null,
|
|
1294
|
-
markersEnabled:
|
|
1295
|
-
regions: [],
|
|
1296
|
-
dragging: false
|
|
652
|
+
markersEnabled: this.props.markersEnabled === undefined ? true : this.props.markersEnabled,
|
|
653
|
+
regions: [],
|
|
654
|
+
dragging: false
|
|
1297
655
|
};
|
|
1298
|
-
|
|
1299
656
|
this.markers = {};
|
|
1300
|
-
|
|
1301
657
|
if (this.props.target) {
|
|
1302
|
-
this.shadow = this.container.attachShadow({
|
|
658
|
+
this.shadow = this.container.attachShadow({
|
|
659
|
+
mode: 'open'
|
|
660
|
+
});
|
|
1303
661
|
this.props.target.appendChild(this.container);
|
|
1304
|
-
// attach styles
|
|
1305
662
|
this.style = document.createElement('style');
|
|
1306
663
|
this.style.type = 'text/css';
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
const fillColor = (this.props.fillColor) ? this.props.fillColor : constants.defaults.fillColor;
|
|
1311
|
-
|
|
1312
|
-
this.style.innerHTML = CSS$1(sanitize(bgColor), sanitize(fillColor));
|
|
664
|
+
const bgColor = this.props.bgColor ? this.props.bgColor : constants.defaults.bgColor;
|
|
665
|
+
const fillColor = this.props.fillColor ? this.props.fillColor : constants.defaults.fillColor;
|
|
666
|
+
this.style.innerHTML = CSS(sanitize(bgColor), sanitize(fillColor));
|
|
1313
667
|
this.shadow.appendChild(this.style);
|
|
1314
668
|
}
|
|
1315
|
-
|
|
1316
669
|
this.bindEvents();
|
|
1317
670
|
this.draw();
|
|
1318
671
|
this.bindHotkeys();
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
when the player metadata is ready (duration data is there)
|
|
1323
|
-
*/
|
|
1324
|
-
const { player } = this.props;
|
|
672
|
+
const {
|
|
673
|
+
player
|
|
674
|
+
} = this.props;
|
|
1325
675
|
if (player) {
|
|
1326
676
|
player.videojs.on('loadedmetadata', () => {
|
|
1327
677
|
this.handleNewProps(this.props);
|
|
1328
678
|
});
|
|
1329
679
|
}
|
|
1330
680
|
}
|
|
1331
|
-
|
|
1332
|
-
/*
|
|
1333
|
-
Video.js seekbar works a bit differently - it
|
|
1334
|
-
sets an interval and checks the playback position
|
|
1335
|
-
very frequently, could do it that way -
|
|
1336
|
-
then could use requestAnimationFrame and
|
|
1337
|
-
get a smoother animation at more expense
|
|
1338
|
-
*/
|
|
1339
|
-
bindEvents() { // bind to vdt player instance
|
|
681
|
+
bindEvents() {
|
|
1340
682
|
if (this.props.player) {
|
|
1341
|
-
const {
|
|
683
|
+
const {
|
|
684
|
+
player
|
|
685
|
+
} = this.props;
|
|
1342
686
|
player.videojs.on('timeupdate', () => {
|
|
1343
687
|
const progressFraction = player.videojs.currentTime() / player.videojs.duration();
|
|
1344
|
-
this.fill.style.width =
|
|
688
|
+
this.fill.style.width = "".concat(100 * progressFraction, "%");
|
|
1345
689
|
});
|
|
1346
|
-
|
|
1347
690
|
player.videojs.on('progress', () => {
|
|
1348
691
|
this.percentLoaded = player.percentLoaded;
|
|
1349
692
|
});
|
|
1350
693
|
}
|
|
1351
694
|
}
|
|
1352
|
-
|
|
1353
695
|
bindHotkeys() {
|
|
1354
696
|
this.bindings = [];
|
|
1355
|
-
|
|
1356
|
-
// bindings related to player
|
|
1357
697
|
if (this.props.player) {
|
|
1358
|
-
const {
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
}
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
{
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
},
|
|
1383
|
-
},
|
|
1384
|
-
];
|
|
698
|
+
const {
|
|
699
|
+
player
|
|
700
|
+
} = this.props;
|
|
701
|
+
this.bindings = [{
|
|
702
|
+
key: ['i'],
|
|
703
|
+
method: () => {
|
|
704
|
+
if (this.markersEnabled) this.in = player.videojs.currentTime();
|
|
705
|
+
}
|
|
706
|
+
}, {
|
|
707
|
+
key: ['o'],
|
|
708
|
+
method: () => {
|
|
709
|
+
if (this.markersEnabled) this.out = player.videojs.currentTime();
|
|
710
|
+
}
|
|
711
|
+
}, {
|
|
712
|
+
key: ['shift+i'],
|
|
713
|
+
method: () => {
|
|
714
|
+
if (this.markersEnabled) this.navigateToIn();
|
|
715
|
+
}
|
|
716
|
+
}, {
|
|
717
|
+
key: ['shift+o'],
|
|
718
|
+
method: () => {
|
|
719
|
+
if (this.markersEnabled) this.navigateToOut();
|
|
720
|
+
}
|
|
721
|
+
}];
|
|
1385
722
|
}
|
|
1386
|
-
|
|
1387
723
|
if (this.props.player) {
|
|
1388
|
-
const {
|
|
724
|
+
const {
|
|
725
|
+
player
|
|
726
|
+
} = this.props;
|
|
1389
727
|
mousetrap__default["default"].bind('i', () => {
|
|
1390
728
|
if (this.markersEnabled) this.in = player.videojs.currentTime();
|
|
1391
729
|
});
|
|
1392
|
-
|
|
1393
730
|
mousetrap__default["default"].bind('o', () => {
|
|
1394
731
|
if (this.markersEnabled) this.out = player.videojs.currentTime();
|
|
1395
732
|
});
|
|
1396
|
-
|
|
1397
733
|
mousetrap__default["default"].bind('shift+i', () => {
|
|
1398
734
|
if (this.markersEnabled) this.navigateToIn();
|
|
1399
735
|
});
|
|
1400
|
-
|
|
1401
736
|
mousetrap__default["default"].bind('shift+o', () => {
|
|
1402
737
|
if (this.markersEnabled) this.navigateToOut();
|
|
1403
738
|
});
|
|
1404
739
|
}
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
this.bindings.forEach((binding) => {
|
|
1408
|
-
mousetrap__default["default"].bind(binding.key, (e) => {
|
|
740
|
+
this.bindings.forEach(binding => {
|
|
741
|
+
mousetrap__default["default"].bind(binding.key, e => {
|
|
1409
742
|
binding.method(e);
|
|
1410
743
|
});
|
|
1411
744
|
});
|
|
1412
745
|
}
|
|
1413
|
-
|
|
1414
746
|
unbindHotKeys() {
|
|
1415
|
-
this.bindings && this.bindings.forEach(
|
|
747
|
+
this.bindings && this.bindings.forEach(binding => {
|
|
1416
748
|
mousetrap__default["default"].unbind(binding.key);
|
|
1417
749
|
});
|
|
1418
750
|
}
|
|
1419
|
-
|
|
1420
751
|
handleSeek(event) {
|
|
1421
|
-
// check if target is a region
|
|
1422
752
|
if (this.props.player) {
|
|
1423
|
-
const {
|
|
753
|
+
const {
|
|
754
|
+
player
|
|
755
|
+
} = this.props;
|
|
1424
756
|
if (this.state.regions) {
|
|
1425
757
|
let clickedOnRegion = false;
|
|
1426
|
-
let preventSeek = false;
|
|
1427
|
-
this.state.regions.forEach(
|
|
758
|
+
let preventSeek = false;
|
|
759
|
+
this.state.regions.forEach(region => {
|
|
1428
760
|
if (region.el.contains(event.target)) {
|
|
1429
|
-
// player.seekTo(region.in);
|
|
1430
|
-
|
|
1431
|
-
// callback for clicking on a region, if callback returns false, no seek happens
|
|
1432
|
-
// TODO - make a convention of returning true / false to break from seek
|
|
1433
761
|
if (this.props.onRegionClick) {
|
|
1434
|
-
preventSeek =
|
|
762
|
+
preventSeek = this.props.onRegionClick(region);
|
|
1435
763
|
if (!preventSeek) {
|
|
1436
764
|
player.seekTo(region.in);
|
|
1437
765
|
}
|
|
1438
766
|
} else {
|
|
1439
767
|
player.seekTo(region.in);
|
|
1440
768
|
}
|
|
1441
|
-
|
|
1442
769
|
clickedOnRegion = true;
|
|
1443
770
|
}
|
|
1444
771
|
});
|
|
1445
|
-
|
|
1446
|
-
/*
|
|
1447
|
-
exit from method, TODO - implement foreach
|
|
1448
|
-
for breaking more efficiently
|
|
1449
|
-
*/
|
|
1450
|
-
|
|
1451
772
|
if (clickedOnRegion) return;
|
|
1452
773
|
}
|
|
1453
|
-
|
|
1454
774
|
const seekFractionX = (event.clientX - this.bar.getBoundingClientRect().left) / this.bar.offsetWidth;
|
|
1455
|
-
// -> 0.34732
|
|
1456
|
-
|
|
1457
775
|
const timeToSeek = seekFractionX * player.videojs.duration();
|
|
1458
|
-
// -> something like 32.2323 (in seconds)
|
|
1459
776
|
player.seekTo(timeToSeek);
|
|
1460
|
-
}
|
|
777
|
+
}
|
|
1461
778
|
}
|
|
1462
|
-
|
|
1463
779
|
handleSeekDrag(mouseDownEvent) {
|
|
1464
|
-
const barOffset = this.bar.getBoundingClientRect().left;
|
|
1465
|
-
const barWidth = this.bar.getBoundingClientRect().width;
|
|
1466
|
-
const duration = this.props.player.videojs.duration();
|
|
780
|
+
const barOffset = this.bar.getBoundingClientRect().left;
|
|
781
|
+
const barWidth = this.bar.getBoundingClientRect().width;
|
|
782
|
+
const duration = this.props.player.videojs.duration();
|
|
1467
783
|
let left;
|
|
1468
|
-
|
|
1469
|
-
const drag = (e) => {
|
|
784
|
+
const drag = e => {
|
|
1470
785
|
left = e.clientX - barOffset;
|
|
1471
786
|
const pxDragged = Math.abs(mouseDownEvent.clientX - e.clientX);
|
|
1472
|
-
|
|
1473
|
-
if (left >= 0 && left < barWidth && pxDragged > 1) { // prevent out-of-bounds
|
|
787
|
+
if (left >= 0 && left < barWidth && pxDragged > 1) {
|
|
1474
788
|
this.dragging = true;
|
|
1475
789
|
const fractionFromStart = parseFloat(left) / barWidth;
|
|
1476
790
|
const seconds = fractionFromStart * duration;
|
|
1477
791
|
this.props.player.videojs.currentTime(seconds);
|
|
1478
792
|
}
|
|
1479
|
-
|
|
1480
793
|
e.preventDefault();
|
|
1481
794
|
};
|
|
1482
|
-
|
|
1483
|
-
const stopDrag = (e) => {
|
|
795
|
+
const stopDrag = e => {
|
|
1484
796
|
this.dragging = false;
|
|
1485
|
-
|
|
1486
|
-
// remove listeners
|
|
1487
797
|
document.removeEventListener('mousemove', drag, false);
|
|
1488
798
|
document.removeEventListener('mouseup', stopDrag, false);
|
|
1489
|
-
|
|
1490
799
|
const fractionFromStart = parseFloat(left) / barWidth;
|
|
1491
800
|
const seconds = fractionFromStart * duration;
|
|
1492
801
|
this.props.player.videojs.currentTime(seconds);
|
|
1493
|
-
|
|
1494
802
|
e.stopPropagation();
|
|
1495
803
|
};
|
|
1496
|
-
|
|
1497
|
-
// add listeners
|
|
1498
804
|
document.addEventListener('mousemove', drag, false);
|
|
1499
805
|
document.addEventListener('mouseup', stopDrag, false);
|
|
1500
806
|
}
|
|
1501
|
-
|
|
1502
807
|
draw() {
|
|
1503
808
|
this.bar = document.createElement('div');
|
|
1504
809
|
this.bar.className = constants.className;
|
|
1505
|
-
this.bar.onclick =
|
|
810
|
+
this.bar.onclick = e => {
|
|
1506
811
|
if (!e.target.classList.contains('marker') && !e.target.classList.contains('handle')) {
|
|
1507
812
|
this.handleSeek(e);
|
|
1508
813
|
}
|
|
1509
814
|
};
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
this.bar.addEventListener('mousedown', (e) => {
|
|
1514
|
-
e.preventDefault(); // prevents selection cursor
|
|
1515
|
-
|
|
1516
|
-
if (!this.dragging) { // don't attach listeners if something is already dragging
|
|
815
|
+
this.bar.addEventListener('mousedown', e => {
|
|
816
|
+
e.preventDefault();
|
|
817
|
+
if (!this.dragging) {
|
|
1517
818
|
this.handleSeekDrag(e);
|
|
1518
819
|
}
|
|
1519
820
|
}, false);
|
|
1520
|
-
|
|
1521
821
|
this.fill = document.createElement('div');
|
|
1522
822
|
this.fill.className = 'fill';
|
|
1523
|
-
|
|
1524
823
|
this.loadIndicator = document.createElement('div');
|
|
1525
824
|
this.loadIndicator.className = 'load-indicator';
|
|
1526
|
-
|
|
1527
825
|
this.region = document.createElement('div');
|
|
1528
826
|
this.region.className = 'region';
|
|
1529
|
-
|
|
1530
827
|
this.bar.appendChild(this.fill);
|
|
1531
828
|
this.bar.appendChild(this.loadIndicator);
|
|
1532
829
|
this.bar.appendChild(this.region);
|
|
1533
830
|
this.shadow.appendChild(this.bar);
|
|
1534
|
-
|
|
1535
831
|
this.drawMarkers();
|
|
1536
832
|
}
|
|
1537
|
-
|
|
1538
|
-
drawMarkers() { // TODO - add touch events
|
|
833
|
+
drawMarkers() {
|
|
1539
834
|
if (this.markersEnabled) {
|
|
1540
835
|
const markerIn = this.markers[constants.markerTypes.in] = document.createElement('div');
|
|
1541
836
|
const markerOut = this.markers[constants.markerTypes.out] = document.createElement('div');
|
|
1542
|
-
markerIn.className =
|
|
1543
|
-
markerOut.className =
|
|
1544
|
-
|
|
837
|
+
markerIn.className = "marker ".concat(constants.markerTypes.in);
|
|
838
|
+
markerOut.className = "marker ".concat(constants.markerTypes.out);
|
|
1545
839
|
const handleIn = document.createElement('div');
|
|
1546
840
|
const handleOut = document.createElement('div');
|
|
1547
841
|
handleIn.className = handleOut.className = 'handle';
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
e.
|
|
1551
|
-
e.stopPropagation(); // prevent triggering seek bar drag
|
|
1552
|
-
|
|
842
|
+
handleIn.addEventListener('mousedown', e => {
|
|
843
|
+
e.preventDefault();
|
|
844
|
+
e.stopPropagation();
|
|
1553
845
|
this.handleMarkerDrag(markerIn, constants.markerTypes.in, e);
|
|
1554
846
|
}, false);
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
e.
|
|
1558
|
-
e.stopPropagation(); // prevent triggering seek bar drag
|
|
1559
|
-
|
|
847
|
+
handleOut.addEventListener('mousedown', e => {
|
|
848
|
+
e.preventDefault();
|
|
849
|
+
e.stopPropagation();
|
|
1560
850
|
this.handleMarkerDrag(markerOut, constants.markerTypes.out, e);
|
|
1561
851
|
}, false);
|
|
1562
|
-
|
|
1563
852
|
markerIn.appendChild(handleIn);
|
|
1564
853
|
markerOut.appendChild(handleOut);
|
|
1565
|
-
|
|
1566
854
|
this.bar.appendChild(markerIn);
|
|
1567
855
|
this.bar.appendChild(markerOut);
|
|
1568
856
|
}
|
|
1569
857
|
}
|
|
1570
|
-
|
|
1571
858
|
updateMarkers(marker) {
|
|
1572
|
-
this.markers[marker.type].style.left =
|
|
859
|
+
this.markers[marker.type].style.left = "".concat(marker.value * 100, "%");
|
|
1573
860
|
this.markers[marker.type].classList.add('active');
|
|
1574
|
-
|
|
1575
|
-
// check if marker mathes a region and add a classname to it
|
|
1576
861
|
if (this.state.regions) {
|
|
1577
|
-
// check if any region contains in / out matching value
|
|
1578
862
|
const matchingRegions = [];
|
|
1579
|
-
const isRegional =
|
|
863
|
+
const isRegional = matchingRegions.length > 0;
|
|
1580
864
|
if (isRegional) {
|
|
1581
865
|
this.markers[marker.type].classList.add('regional');
|
|
1582
866
|
} else {
|
|
1583
867
|
this.markers[marker.type].classList.remove('regional');
|
|
1584
868
|
}
|
|
1585
869
|
}
|
|
1586
|
-
|
|
1587
870
|
this.drawInAndOutRegion();
|
|
1588
871
|
}
|
|
1589
|
-
|
|
1590
|
-
drawInAndOutRegion() { // triggered after drawMarkers if in + out is set
|
|
872
|
+
drawInAndOutRegion() {
|
|
1591
873
|
if (this.state.in !== null && this.state.out !== null) {
|
|
1592
874
|
this.region.style.left = this.markers[constants.markerTypes.in].style.left;
|
|
1593
|
-
this.region.style.right =
|
|
875
|
+
this.region.style.right = "".concat(100 - parseFloat(this.markers[constants.markerTypes.out].style.left.replace('%', '')), "%");
|
|
1594
876
|
}
|
|
1595
877
|
}
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
case before that
|
|
1601
|
-
*/
|
|
1602
|
-
handleMarkerDrag(markerNode, type, mouseDownEvent) { // marker node, marker type (constants.markerTypes)
|
|
1603
|
-
const barOffset = this.bar.getBoundingClientRect().left; // px from page left side
|
|
1604
|
-
const barWidth = this.bar.getBoundingClientRect().width; // seek bar width
|
|
1605
|
-
const duration = this.props.player.videojs.duration(); // in secondsā
|
|
878
|
+
handleMarkerDrag(markerNode, type, mouseDownEvent) {
|
|
879
|
+
const barOffset = this.bar.getBoundingClientRect().left;
|
|
880
|
+
const barWidth = this.bar.getBoundingClientRect().width;
|
|
881
|
+
const duration = this.props.player.videojs.duration();
|
|
1606
882
|
let dragHappened = false;
|
|
1607
|
-
|
|
1608
|
-
const drag = (e) => {
|
|
883
|
+
const drag = e => {
|
|
1609
884
|
const pxDragged = Math.abs(mouseDownEvent.clientX - e.clientX);
|
|
1610
|
-
const markerOffset =
|
|
885
|
+
const markerOffset = type === constants.markerTypes.in ? constants.defaults.markerWidth / 2 : -(constants.defaults.markerWidth / 2);
|
|
1611
886
|
const left = e.clientX - barOffset + markerOffset;
|
|
1612
|
-
|
|
1613
|
-
if (left >= 0 && left < barWidth && pxDragged > 1) { // prevent out-of-bounds
|
|
887
|
+
if (left >= 0 && left < barWidth && pxDragged > 1) {
|
|
1614
888
|
dragHappened = this.dragging = true;
|
|
1615
|
-
markerNode.style.left =
|
|
889
|
+
markerNode.style.left = "".concat(left, "px");
|
|
1616
890
|
markerNode.classList.add('active');
|
|
1617
|
-
|
|
1618
891
|
const fractionFromStart = parseFloat(markerNode.getBoundingClientRect().left - barOffset) / barWidth;
|
|
1619
892
|
const seconds = fractionFromStart * duration;
|
|
1620
893
|
this.props.player.videojs.currentTime(seconds);
|
|
1621
894
|
}
|
|
1622
|
-
|
|
1623
895
|
e.preventDefault();
|
|
1624
896
|
};
|
|
1625
|
-
|
|
1626
|
-
const stopDrag = (e) => {
|
|
897
|
+
const stopDrag = e => {
|
|
1627
898
|
this.dragging = false;
|
|
1628
|
-
|
|
1629
|
-
// remove listeners
|
|
1630
899
|
document.removeEventListener('mousemove', drag, false);
|
|
1631
900
|
document.removeEventListener('mouseup', stopDrag, false);
|
|
1632
|
-
|
|
1633
901
|
const fractionFromStart = parseFloat(markerNode.getBoundingClientRect().left - barOffset) / barWidth;
|
|
1634
902
|
const seconds = fractionFromStart * duration;
|
|
1635
903
|
this[type] = seconds;
|
|
1636
904
|
this.props.player.videojs.currentTime(seconds);
|
|
1637
|
-
|
|
1638
|
-
/*
|
|
1639
|
-
if drag did not take place,
|
|
1640
|
-
user just clicked the marker -
|
|
1641
|
-
jump to the time of marker in player
|
|
1642
|
-
*/
|
|
1643
905
|
if (!dragHappened) {
|
|
1644
906
|
if (type === constants.markerTypes.in) {
|
|
1645
907
|
this.navigateToIn();
|
|
@@ -1647,121 +909,99 @@
|
|
|
1647
909
|
this.navigateToOut();
|
|
1648
910
|
}
|
|
1649
911
|
}
|
|
1650
|
-
|
|
1651
|
-
|
|
912
|
+
this.props.onDragFinish && this.props.onDragFinish({
|
|
913
|
+
type,
|
|
914
|
+
seconds
|
|
915
|
+
});
|
|
1652
916
|
e.stopPropagation();
|
|
1653
917
|
};
|
|
1654
|
-
|
|
1655
|
-
// add listeners
|
|
1656
918
|
document.addEventListener('mousemove', drag, false);
|
|
1657
919
|
document.addEventListener('mouseup', stopDrag, false);
|
|
1658
920
|
}
|
|
1659
|
-
|
|
1660
|
-
/*
|
|
1661
|
-
hide dead markers (for state parity) or ones that
|
|
1662
|
-
make no sense (like out point before in point)
|
|
1663
|
-
*/
|
|
1664
921
|
cleanupMarkers() {
|
|
1665
922
|
let removedMarker = false;
|
|
1666
923
|
if (this.state.in === null) {
|
|
1667
924
|
this.markers[constants.markerTypes.in].classList.remove('active');
|
|
1668
925
|
removedMarker = true;
|
|
1669
926
|
}
|
|
1670
|
-
|
|
1671
927
|
if (this.state.out === null) {
|
|
1672
928
|
this.markers[constants.markerTypes.out].classList.remove('active');
|
|
1673
929
|
removedMarker = true;
|
|
1674
930
|
}
|
|
1675
|
-
|
|
1676
|
-
if (removedMarker) { // if a marker was removed, region no longer is valid
|
|
931
|
+
if (removedMarker) {
|
|
1677
932
|
this.region.style.left = 'initial';
|
|
1678
933
|
this.region.style.right = 'initial';
|
|
1679
934
|
}
|
|
1680
935
|
}
|
|
1681
|
-
|
|
1682
936
|
clearMarkers() {
|
|
1683
937
|
this.in = null;
|
|
1684
938
|
this.out = null;
|
|
1685
939
|
}
|
|
1686
|
-
|
|
1687
|
-
// utilizes player instance from props
|
|
1688
940
|
setInFromCurrent() {
|
|
1689
941
|
this.in = this.props.player.videojs.currentTime();
|
|
1690
942
|
}
|
|
1691
|
-
|
|
1692
943
|
setOutFromCurrent() {
|
|
1693
944
|
this.out = this.props.player.videojs.currentTime();
|
|
1694
945
|
}
|
|
1695
|
-
|
|
1696
946
|
navigateToIn() {
|
|
1697
|
-
const {
|
|
947
|
+
const {
|
|
948
|
+
player
|
|
949
|
+
} = this.props;
|
|
1698
950
|
player.seekTo(this.in);
|
|
1699
951
|
}
|
|
1700
|
-
|
|
1701
952
|
navigateToOut() {
|
|
1702
|
-
const {
|
|
953
|
+
const {
|
|
954
|
+
player
|
|
955
|
+
} = this.props;
|
|
1703
956
|
player.seekTo(this.out);
|
|
1704
957
|
}
|
|
1705
|
-
|
|
1706
|
-
// setters and getters
|
|
1707
958
|
set in(val) {
|
|
1708
959
|
if (!this.state.markersEnabled) return;
|
|
1709
|
-
|
|
1710
960
|
this.state.in = val;
|
|
1711
|
-
|
|
1712
961
|
if (val !== null && val !== undefined) {
|
|
1713
|
-
const {
|
|
962
|
+
const {
|
|
963
|
+
player
|
|
964
|
+
} = this.props;
|
|
1714
965
|
this.updateMarkers({
|
|
1715
966
|
type: constants.markerTypes.in,
|
|
1716
|
-
value: val / player.videojs.duration()
|
|
967
|
+
value: val / player.videojs.duration()
|
|
1717
968
|
});
|
|
1718
|
-
|
|
1719
|
-
// make sure in point is not set after out point
|
|
1720
969
|
if (this.state.out !== null && val > this.state.out) {
|
|
1721
970
|
this.out = null;
|
|
1722
971
|
}
|
|
1723
|
-
|
|
1724
972
|
this.props.onIn && this.props.onIn(this.state.in);
|
|
1725
973
|
} else {
|
|
1726
974
|
this.cleanupMarkers();
|
|
1727
975
|
}
|
|
1728
976
|
}
|
|
1729
|
-
|
|
1730
977
|
get in() {
|
|
1731
978
|
return this.state.in;
|
|
1732
979
|
}
|
|
1733
|
-
|
|
1734
980
|
set out(val) {
|
|
1735
981
|
if (!this.state.markersEnabled) return;
|
|
1736
|
-
|
|
1737
982
|
this.state.out = val;
|
|
1738
|
-
|
|
1739
983
|
if (val !== null && val !== undefined) {
|
|
1740
|
-
const {
|
|
984
|
+
const {
|
|
985
|
+
player
|
|
986
|
+
} = this.props;
|
|
1741
987
|
this.updateMarkers({
|
|
1742
988
|
type: constants.markerTypes.out,
|
|
1743
|
-
value: val / player.videojs.duration()
|
|
989
|
+
value: val / player.videojs.duration()
|
|
1744
990
|
});
|
|
1745
|
-
|
|
1746
|
-
// make sure out point is not set before in point
|
|
1747
991
|
if (this.state.in != null && val < this.state.in) {
|
|
1748
992
|
this.in = null;
|
|
1749
993
|
}
|
|
1750
|
-
|
|
1751
994
|
this.props.onOut && this.props.onOut(this.state.out);
|
|
1752
995
|
} else {
|
|
1753
996
|
this.cleanupMarkers();
|
|
1754
997
|
}
|
|
1755
998
|
}
|
|
1756
|
-
|
|
1757
999
|
get out() {
|
|
1758
1000
|
return this.state.out;
|
|
1759
1001
|
}
|
|
1760
|
-
|
|
1761
1002
|
get markersEnabled() {
|
|
1762
1003
|
return this.state.markersEnabled;
|
|
1763
1004
|
}
|
|
1764
|
-
|
|
1765
1005
|
set markersEnabled(bool) {
|
|
1766
1006
|
if (typeof bool === 'boolean') {
|
|
1767
1007
|
if (!bool) {
|
|
@@ -1773,28 +1013,23 @@
|
|
|
1773
1013
|
}
|
|
1774
1014
|
}
|
|
1775
1015
|
}
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
regionArray && regionArray.forEach((region) => {
|
|
1016
|
+
set regions(regionArray) {
|
|
1017
|
+
if (this.state.regions.length < 1) {
|
|
1018
|
+
regionArray && regionArray.forEach(region => {
|
|
1780
1019
|
this.addRegion(region);
|
|
1781
1020
|
});
|
|
1782
|
-
} else {
|
|
1021
|
+
} else {
|
|
1783
1022
|
this.state.regions.forEach((region, index) => {
|
|
1784
1023
|
this.removeRegion(index);
|
|
1785
1024
|
});
|
|
1786
|
-
|
|
1787
1025
|
this.state.regions = [];
|
|
1788
|
-
this.regions = regionArray;
|
|
1026
|
+
this.regions = regionArray;
|
|
1789
1027
|
}
|
|
1790
1028
|
}
|
|
1791
|
-
|
|
1792
1029
|
get regions() {
|
|
1793
1030
|
return this.state.regions;
|
|
1794
1031
|
}
|
|
1795
|
-
|
|
1796
1032
|
set dragging(bool) {
|
|
1797
|
-
// update only if worth updating
|
|
1798
1033
|
if (bool && !this.state.dragging) {
|
|
1799
1034
|
this.state.dragging = true;
|
|
1800
1035
|
this.bar.classList.add('dragging');
|
|
@@ -1803,109 +1038,269 @@
|
|
|
1803
1038
|
this.bar.classList.remove('dragging');
|
|
1804
1039
|
}
|
|
1805
1040
|
}
|
|
1806
|
-
|
|
1807
1041
|
get dragging() {
|
|
1808
1042
|
return this.state.dragging;
|
|
1809
1043
|
}
|
|
1810
|
-
|
|
1811
1044
|
addRegion(regionObj) {
|
|
1812
1045
|
if (regionObj.constructor.name === Region.name) {
|
|
1813
1046
|
this.state.regions.push(regionObj);
|
|
1814
1047
|
this.drawRegion(regionObj);
|
|
1815
|
-
} else {
|
|
1048
|
+
} else {
|
|
1816
1049
|
this.addRegion(new Region(regionObj));
|
|
1817
1050
|
}
|
|
1818
1051
|
}
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
this.state.regions[param]
|
|
1823
|
-
this.state.regions[param]
|
|
1824
|
-
|
|
1825
|
-
|
|
1052
|
+
removeRegion(param) {
|
|
1053
|
+
if (typeof param === typeof Region) ; else {
|
|
1054
|
+
this.state.regions[param].el.remove();
|
|
1055
|
+
this.state.regions[param] = null;
|
|
1056
|
+
delete this.state.regions[param];
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
drawRegion(region) {
|
|
1060
|
+
const duration = this.props.player.videojs.duration();
|
|
1061
|
+
const inPoint = region.in;
|
|
1062
|
+
const leftPercentage = inPoint / duration * 100;
|
|
1063
|
+
const rightPercentage = (duration - region.out) / duration * 100;
|
|
1064
|
+
const regionEl = document.createElement('div');
|
|
1065
|
+
regionEl.className = 'region nav ';
|
|
1066
|
+
regionEl.innerHTML = '<div class="bubble"></div>';
|
|
1067
|
+
if (region.title && region.annotation) {
|
|
1068
|
+
let alignmentClassName = '';
|
|
1069
|
+
if (leftPercentage > 70) alignmentClassName = 'right-aligned';
|
|
1070
|
+
if (leftPercentage < 30) alignmentClassName = 'left-aligned';
|
|
1071
|
+
regionEl.className += " has-popout ".concat(alignmentClassName);
|
|
1072
|
+
const popout = document.createElement('div');
|
|
1073
|
+
popout.className = 'popout';
|
|
1074
|
+
popout.innerHTML = "\n <div class=\"title\">\n ".concat(sanitize(region.title), "\n </div>\n <div class=\"annotation\">\n ").concat(truncate(sanitize(region.annotation), 72), "\n </div>\n ");
|
|
1075
|
+
regionEl.appendChild(popout);
|
|
1076
|
+
}
|
|
1077
|
+
regionEl.style.left = "".concat(leftPercentage, "%");
|
|
1078
|
+
regionEl.style.right = "".concat(rightPercentage, "%");
|
|
1079
|
+
region.el = regionEl;
|
|
1080
|
+
this.bar.appendChild(regionEl);
|
|
1081
|
+
}
|
|
1082
|
+
set onDark(bool) {
|
|
1083
|
+
if (bool) {
|
|
1084
|
+
this.bar.classList.add(classNames.onDark);
|
|
1085
|
+
} else {
|
|
1086
|
+
this.bar.classList.remove(classNames.onDark);
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
get onDark() {
|
|
1090
|
+
return this.container.classList.contains(classNames.onDark);
|
|
1091
|
+
}
|
|
1092
|
+
set percentLoaded(val) {
|
|
1093
|
+
this.loadIndicator.style.width = "".concat(val, "%");
|
|
1094
|
+
}
|
|
1095
|
+
destroy() {
|
|
1096
|
+
this.unbindHotKeys();
|
|
1097
|
+
}
|
|
1098
|
+
toggleMarkers() {
|
|
1099
|
+
if (this.bar.classList.contains('hide-markers')) {
|
|
1100
|
+
this.showMarkers();
|
|
1101
|
+
} else {
|
|
1102
|
+
this.hideMarkers();
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
hideMarkers() {
|
|
1106
|
+
this.bar.classList.add('hide-markers');
|
|
1107
|
+
}
|
|
1108
|
+
showMarkers() {
|
|
1109
|
+
this.bar.classList.remove('hide-markers');
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
SeekBar.Region = Region;
|
|
1113
|
+
|
|
1114
|
+
const timeCodeNodeNames = ['hours', 'minutes', 'seconds', 'frame'];
|
|
1115
|
+
class TimeCodeDisplay {
|
|
1116
|
+
constructor(props) {
|
|
1117
|
+
this.props = props;
|
|
1118
|
+
this.state = {
|
|
1119
|
+
selectedNode: null
|
|
1120
|
+
};
|
|
1121
|
+
const classNames = ['vdt-timecode', 'vjs-time-control',
|
|
1122
|
+
!this.props.onInput ? 'duration' : ''
|
|
1123
|
+
];
|
|
1124
|
+
this.container = document.createElement('div');
|
|
1125
|
+
this.container.className = classNames.join(' ');
|
|
1126
|
+
this.nodeNames = [].concat(timeCodeNodeNames);
|
|
1127
|
+
this.nodes = {};
|
|
1128
|
+
this.nodeNames.forEach((nodeName, index) => {
|
|
1129
|
+
const node = document.createElement('input');
|
|
1130
|
+
node.className = nodeName;
|
|
1131
|
+
node.tabIndex = -1;
|
|
1132
|
+
if (this.props.onInput) {
|
|
1133
|
+
node.maxLength = 2;
|
|
1134
|
+
node.onfocus = e => {
|
|
1135
|
+
this.handleInputFocus(e, nodeName);
|
|
1136
|
+
};
|
|
1137
|
+
node.onblur = e => {
|
|
1138
|
+
this.handleInputBlur(e, nodeName);
|
|
1139
|
+
};
|
|
1140
|
+
node.onmouseup = e => {
|
|
1141
|
+
e.preventDefault();
|
|
1142
|
+
e.currentTarget.select();
|
|
1143
|
+
};
|
|
1144
|
+
node.onkeydown = e => {
|
|
1145
|
+
this.handleTimeCodeInput(e, nodeName);
|
|
1146
|
+
};
|
|
1147
|
+
node.onkeyup = e => {
|
|
1148
|
+
this.handleTimeCodeInputOnKeyUp(e, nodeName);
|
|
1149
|
+
};
|
|
1150
|
+
} else {
|
|
1151
|
+
node.readOnly = true;
|
|
1152
|
+
}
|
|
1153
|
+
this.nodes[nodeName] = node;
|
|
1154
|
+
const colon = document.createElement('span');
|
|
1155
|
+
colon.innerHTML = ':';
|
|
1156
|
+
this.container.appendChild(node);
|
|
1157
|
+
index !== this.nodeNames.length - 1 && this.container.appendChild(colon);
|
|
1158
|
+
});
|
|
1159
|
+
if (this.props.target) {
|
|
1160
|
+
if (this.props.appendAfter) {
|
|
1161
|
+
this.props.target.parentNode.insertBefore(this.container, this.props.target.nextSibling);
|
|
1162
|
+
} else {
|
|
1163
|
+
this.props.target.appendChild(this.container);
|
|
1164
|
+
}
|
|
1165
|
+
this.reset();
|
|
1166
|
+
} else {
|
|
1167
|
+
console.error("Unable to instantiate a new ".concat(this.constructor.name, " without target DOM node"));
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
update(valuesObj) {
|
|
1171
|
+
const startCount = this.nodeNames.length - 1;
|
|
1172
|
+
let i;
|
|
1173
|
+
for (i = startCount; i > -1; i--) {
|
|
1174
|
+
const key = this.nodeNames[i];
|
|
1175
|
+
if (typeof valuesObj[key] !== 'undefined' && valuesObj[key] !== parseInt(this.nodes[key].value, 10) && key !== this.state.selectedNode) {
|
|
1176
|
+
const str = valuesObj[key].toString();
|
|
1177
|
+
this.nodes[key].value = this.toDigitPairStr(str);
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
reset() {
|
|
1182
|
+
this.update({
|
|
1183
|
+
hours: 0,
|
|
1184
|
+
minutes: 0,
|
|
1185
|
+
seconds: 0,
|
|
1186
|
+
frame: 0
|
|
1187
|
+
});
|
|
1188
|
+
}
|
|
1189
|
+
handleInputFocus(e, nodeName) {
|
|
1190
|
+
this.state.selectedNode = nodeName;
|
|
1191
|
+
this.nodes[nodeName].select();
|
|
1192
|
+
this.props.onInputFocus && this.props.onInputFocus(nodeName);
|
|
1193
|
+
}
|
|
1194
|
+
handleInputBlur(e, nodeName) {
|
|
1195
|
+
this.state.selectedNode = null;
|
|
1196
|
+
this.props.onInputBlur && this.props.onInputBlur(nodeName);
|
|
1197
|
+
}
|
|
1198
|
+
sanitize(input) {
|
|
1199
|
+
const output = input.replace(/[^0-9]/g, '');
|
|
1200
|
+
return output;
|
|
1201
|
+
}
|
|
1202
|
+
toDigitPairStr(strValue) {
|
|
1203
|
+
return strValue.length < 2 ? "0".concat(strValue) : strValue;
|
|
1204
|
+
}
|
|
1205
|
+
handleTimeCodeInput(e, nodeName) {
|
|
1206
|
+
const nodeIndex = this.nodeNames.indexOf(nodeName);
|
|
1207
|
+
switch (e.code) {
|
|
1208
|
+
case 'Enter':
|
|
1209
|
+
this.checkAndNormalizeAllInputs();
|
|
1210
|
+
this.props.onInput && this.props.onInput(e, nodeName, {
|
|
1211
|
+
hours: this.hours,
|
|
1212
|
+
minutes: this.minutes,
|
|
1213
|
+
seconds: this.seconds,
|
|
1214
|
+
frame: this.frame
|
|
1215
|
+
});
|
|
1216
|
+
this[nodeName] = e.currentTarget.value;
|
|
1217
|
+
e.currentTarget.blur();
|
|
1218
|
+
break;
|
|
1219
|
+
case 'Tab':
|
|
1220
|
+
e.preventDefault();
|
|
1221
|
+
if (!e.shiftKey) {
|
|
1222
|
+
if (nodeIndex + 1 <= this.nodeNames.length - 1) {
|
|
1223
|
+
this.nodes[this.nodeNames[nodeIndex + 1]].focus();
|
|
1224
|
+
} else {
|
|
1225
|
+
this.nodes[this.nodeNames[0]].focus();
|
|
1226
|
+
}
|
|
1227
|
+
} else if (nodeIndex - 1 >= 0) {
|
|
1228
|
+
this.nodes[this.nodeNames[nodeIndex - 1]].focus();
|
|
1229
|
+
} else {
|
|
1230
|
+
this.nodes[this.nodeNames[this.nodeNames.length - 1]].focus();
|
|
1231
|
+
}
|
|
1232
|
+
break;
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
handleTimeCodeInputOnKeyUp(e, nodeName) {
|
|
1236
|
+
if (this.nodes[nodeName].value.length === 2 && !isNaN(e.key)) {
|
|
1237
|
+
const nodeIndex = this.nodeNames.indexOf(nodeName);
|
|
1238
|
+
if (nodeIndex + 1 <= this.nodeNames.length - 1) {
|
|
1239
|
+
this.nodes[this.nodeNames[nodeIndex + 1]].focus();
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
checkAndNormalizeAllInputs() {
|
|
1244
|
+
this.nodeNames.forEach(nodeName => {
|
|
1245
|
+
if (this.nodes[nodeName].value.length < 1) {
|
|
1246
|
+
this.nodes[nodeName].value = '00';
|
|
1247
|
+
}
|
|
1248
|
+
this.nodes[nodeName].value = this.toDigitPairStr(this.sanitize(this.nodes[nodeName].value));
|
|
1249
|
+
});
|
|
1250
|
+
}
|
|
1251
|
+
set frame(val) {
|
|
1252
|
+
this.nodes.frame.value = this.toDigitPairStr(val);
|
|
1253
|
+
}
|
|
1254
|
+
get frame() {
|
|
1255
|
+
return parseInt(this.nodes.frame.value, 10);
|
|
1256
|
+
}
|
|
1257
|
+
set seconds(val) {
|
|
1258
|
+
this.nodes.seconds.value = this.toDigitPairStr(val);
|
|
1259
|
+
}
|
|
1260
|
+
get seconds() {
|
|
1261
|
+
return parseInt(this.nodes.seconds.value, 10);
|
|
1262
|
+
}
|
|
1263
|
+
set minutes(val) {
|
|
1264
|
+
this.nodes.minutes.value = this.toDigitPairStr(val);
|
|
1265
|
+
}
|
|
1266
|
+
get minutes() {
|
|
1267
|
+
return parseInt(this.nodes.minutes.value, 10);
|
|
1268
|
+
}
|
|
1269
|
+
set hours(val) {
|
|
1270
|
+
this.nodes.hours.value = this.toDigitPairStr(val);
|
|
1826
1271
|
}
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
const duration = this.props.player.videojs.duration(); // seconds
|
|
1830
|
-
const inPoint = region.in;
|
|
1831
|
-
|
|
1832
|
-
const leftPercentage = (inPoint / duration) * 100;
|
|
1833
|
-
const rightPercentage = ((duration - region.out) / duration) * 100;
|
|
1834
|
-
|
|
1835
|
-
const regionEl = document.createElement('div');
|
|
1836
|
-
regionEl.className = 'region nav ';
|
|
1837
|
-
regionEl.innerHTML = '<div class="bubble"></div>';
|
|
1838
|
-
|
|
1839
|
-
if (region.title && region.annotation) {
|
|
1840
|
-
let alignmentClassName = '';
|
|
1841
|
-
if (leftPercentage > 70) alignmentClassName = 'right-aligned';
|
|
1842
|
-
if (leftPercentage < 30) alignmentClassName = 'left-aligned';
|
|
1843
|
-
regionEl.className += ` has-popout ${alignmentClassName}`;
|
|
1844
|
-
|
|
1845
|
-
const popout = document.createElement('div');
|
|
1846
|
-
|
|
1847
|
-
popout.className = 'popout';
|
|
1848
|
-
popout.innerHTML = `
|
|
1849
|
-
<div class="title">
|
|
1850
|
-
${sanitize(region.title)}
|
|
1851
|
-
</div>
|
|
1852
|
-
<div class="annotation">
|
|
1853
|
-
${truncate(sanitize(region.annotation), 72)}
|
|
1854
|
-
</div>
|
|
1855
|
-
`;
|
|
1856
|
-
|
|
1857
|
-
regionEl.appendChild(popout);
|
|
1858
|
-
}
|
|
1859
|
-
|
|
1860
|
-
regionEl.style.left = `${leftPercentage}%`;
|
|
1861
|
-
regionEl.style.right = `${rightPercentage}%`;
|
|
1862
|
-
|
|
1863
|
-
region.el = regionEl;
|
|
1864
|
-
|
|
1865
|
-
this.bar.appendChild(regionEl);
|
|
1272
|
+
get hours() {
|
|
1273
|
+
return parseInt(this.nodes.hours.value, 10);
|
|
1866
1274
|
}
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
if (bool) {
|
|
1870
|
-
this.bar.classList.add(classNames.onDark);
|
|
1871
|
-
} else {
|
|
1872
|
-
this.bar.classList.remove(classNames.onDark);
|
|
1873
|
-
}
|
|
1275
|
+
getFormatted(key) {
|
|
1276
|
+
return this.toDigitPairStr(this[key].toString());
|
|
1874
1277
|
}
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1278
|
+
get smpte() {
|
|
1279
|
+
return {
|
|
1280
|
+
hours: this.hours,
|
|
1281
|
+
minutes: this.minutes,
|
|
1282
|
+
seconds: this.seconds,
|
|
1283
|
+
frame: this.frame
|
|
1284
|
+
};
|
|
1878
1285
|
}
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
this.loadIndicator.style.width = `${val}%`;
|
|
1286
|
+
set smpte(o) {
|
|
1287
|
+
this.update(o);
|
|
1882
1288
|
}
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
this.unbindHotKeys();
|
|
1289
|
+
get smpteString() {
|
|
1290
|
+
return "".concat(this.getFormatted('hours'), ":").concat(this.getFormatted('minutes'), ":").concat(this.getFormatted('seconds'), ":").concat(this.getFormatted('frame'));
|
|
1886
1291
|
}
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
this.showMarkers();
|
|
1292
|
+
set external(bool) {
|
|
1293
|
+
if (bool) {
|
|
1294
|
+
this.container.classList.add('external');
|
|
1891
1295
|
} else {
|
|
1892
|
-
this.
|
|
1296
|
+
this.container.classList.remove('external');
|
|
1893
1297
|
}
|
|
1894
1298
|
}
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
this.bar.classList.add('hide-markers');
|
|
1898
|
-
}
|
|
1899
|
-
|
|
1900
|
-
showMarkers() {
|
|
1901
|
-
this.bar.classList.remove('hide-markers');
|
|
1299
|
+
get external() {
|
|
1300
|
+
return this.container.classList.contains('external');
|
|
1902
1301
|
}
|
|
1903
1302
|
}
|
|
1904
1303
|
|
|
1905
|
-
SeekBar.Region = Region;
|
|
1906
|
-
|
|
1907
|
-
// TODO - move this to @vidispine/vdt-js when finalized and use as dependency
|
|
1908
|
-
|
|
1909
1304
|
class VideoTime {
|
|
1910
1305
|
constructor(props) {
|
|
1911
1306
|
if (props.frameRate === undefined) {
|
|
@@ -1915,200 +1310,141 @@
|
|
|
1915
1310
|
this.props = props;
|
|
1916
1311
|
}
|
|
1917
1312
|
}
|
|
1918
|
-
|
|
1919
1313
|
secondsToFramesFromStart(seconds) {
|
|
1920
1314
|
let frame = seconds * this.props.frameRate;
|
|
1921
1315
|
frame = Math.round(frame);
|
|
1922
|
-
return frame;
|
|
1316
|
+
return frame;
|
|
1923
1317
|
}
|
|
1924
|
-
|
|
1925
1318
|
currentTimeToFramesFromStart(currentTime) {
|
|
1926
1319
|
return this.secondsToFramesFromStart(currentTime);
|
|
1927
1320
|
}
|
|
1928
|
-
|
|
1929
1321
|
secondsToFrame(seconds) {
|
|
1930
1322
|
let frame = this.secondsToFramesFromStart(seconds) % this.props.frameRate;
|
|
1931
1323
|
frame = Math.round(frame);
|
|
1932
1324
|
return frame;
|
|
1933
1325
|
}
|
|
1934
|
-
|
|
1935
1326
|
currentFrame(currentTime) {
|
|
1936
1327
|
return Math.round(this.secondsToFrame(currentTime));
|
|
1937
1328
|
}
|
|
1938
|
-
|
|
1939
1329
|
frameToCurrentTimeFromStart(frame) {
|
|
1940
|
-
return frame / this.props.frameRate;
|
|
1330
|
+
return frame / this.props.frameRate;
|
|
1941
1331
|
}
|
|
1942
|
-
|
|
1943
1332
|
smpteToCurrentTimeFromStart(values) {
|
|
1944
|
-
return
|
|
1945
|
-
values.hours * 3600
|
|
1946
|
-
+ values.minutes * 60
|
|
1947
|
-
+ values.seconds
|
|
1948
|
-
+ values.frame / this.props.frameRate
|
|
1949
|
-
);
|
|
1333
|
+
return values.hours * 3600 + values.minutes * 60 + values.seconds + values.frame / this.props.frameRate;
|
|
1950
1334
|
}
|
|
1951
|
-
|
|
1952
1335
|
secondsFromStartToSMPTE(secondsFromStart) {
|
|
1953
1336
|
let secondsFS = secondsFromStart;
|
|
1954
1337
|
const hours = Math.floor(secondsFS / 3600);
|
|
1955
1338
|
const minutesWithoutHours = secondsFS / 60 - 60 * hours;
|
|
1956
|
-
// eslint-disable-next-line no-param-reassign
|
|
1957
1339
|
secondsFS %= 3600;
|
|
1958
|
-
|
|
1959
1340
|
const minutes = Math.floor(minutesWithoutHours);
|
|
1960
1341
|
const seconds = Math.floor(secondsFS % 60);
|
|
1961
1342
|
const frame = this.secondsToFrame(secondsFS);
|
|
1962
|
-
|
|
1963
1343
|
return {
|
|
1964
1344
|
hours,
|
|
1965
1345
|
minutes,
|
|
1966
1346
|
seconds,
|
|
1967
|
-
frame
|
|
1347
|
+
frame
|
|
1968
1348
|
};
|
|
1969
1349
|
}
|
|
1970
1350
|
}
|
|
1971
1351
|
|
|
1972
|
-
|
|
1973
|
-
|
|
1352
|
+
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
1353
|
+
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
|
|
1974
1354
|
const correctMimeTypes = {
|
|
1975
|
-
'audio/x-aac': 'audio/aac'
|
|
1355
|
+
'audio/x-aac': 'audio/aac'
|
|
1976
1356
|
};
|
|
1977
|
-
const sanitizeMimeType =
|
|
1978
|
-
|
|
1357
|
+
const sanitizeMimeType = mimeType => correctMimeTypes[mimeType] || mimeType;
|
|
1979
1358
|
class Player {
|
|
1980
1359
|
constructor(props) {
|
|
1981
|
-
this.props = props;
|
|
1982
|
-
reactiveSetters.apply(this);
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
'video-js',
|
|
1986
|
-
'vjs-big-play-centered',
|
|
1987
|
-
(this.props.posterUrl) ? constants$2.classNames.poster : '',
|
|
1988
|
-
(this.props.subtitles && this.props.subtitles.length > 0) ? constants$2.classNames.subtitles : '',
|
|
1989
|
-
'init', // make player height 0 while no metadata for video size available with css
|
|
1360
|
+
this.props = props;
|
|
1361
|
+
reactiveSetters.apply(this);
|
|
1362
|
+
const classNames = [
|
|
1363
|
+
'video-js', 'vjs-big-play-centered', this.props.posterUrl ? constants$2.classNames.poster : '', this.props.subtitles && this.props.subtitles.length > 0 ? constants$2.classNames.subtitles : '', 'init'
|
|
1990
1364
|
];
|
|
1991
|
-
|
|
1992
1365
|
this.externalTimecodes = {
|
|
1993
|
-
// either one of these can hold an array of TimeCodeDisplay instances
|
|
1994
1366
|
duration: [],
|
|
1995
|
-
playback: []
|
|
1367
|
+
playback: []
|
|
1996
1368
|
};
|
|
1997
|
-
|
|
1998
1369
|
this.timeConverter = new VideoTime({
|
|
1999
|
-
frameRate: this.props.frameRate || constants$2.defaults.frameRate
|
|
1370
|
+
frameRate: this.props.frameRate || constants$2.defaults.frameRate
|
|
2000
1371
|
});
|
|
2001
|
-
|
|
2002
|
-
/*
|
|
2003
|
-
video.js requires a html video to initialize
|
|
2004
|
-
*/
|
|
2005
|
-
|
|
2006
1372
|
this.videoEl = document.createElement('video');
|
|
2007
1373
|
this.videoEl.crossOrigin = this.props.crossOrigin;
|
|
2008
1374
|
this.videoEl.id = 'vdt-video';
|
|
2009
1375
|
this.videoEl.className = classNames.join(' ');
|
|
2010
|
-
this.videoEl.controls = true;
|
|
2011
|
-
|
|
2012
|
-
// attach sources, sort mp4 on top of source list
|
|
1376
|
+
this.videoEl.controls = true;
|
|
2013
1377
|
if (this.props.sources) {
|
|
2014
|
-
// sort mp4 at the top
|
|
2015
1378
|
if (this.props.sources.length > 1) {
|
|
2016
|
-
this.props.sources.sort(
|
|
1379
|
+
this.props.sources.sort(a => a.type.indexOf('mp4') > 0 ? 1 : -1);
|
|
2017
1380
|
}
|
|
2018
|
-
|
|
2019
|
-
// construct <source> els
|
|
2020
|
-
this.props.sources.forEach((source) => {
|
|
1381
|
+
this.props.sources.forEach(source => {
|
|
2021
1382
|
const aSource = document.createElement('source');
|
|
2022
1383
|
aSource.src = source.src;
|
|
2023
1384
|
aSource.type = sanitizeMimeType(source.type);
|
|
2024
1385
|
this.videoEl.appendChild(aSource);
|
|
2025
1386
|
});
|
|
2026
|
-
}
|
|
2027
|
-
|
|
2028
|
-
this.videoEl.onloadedmetadata = () => { // read-only duration timecode
|
|
1387
|
+
}
|
|
1388
|
+
this.videoEl.onloadedmetadata = () => {
|
|
2029
1389
|
if (this.durationTimeCode) {
|
|
2030
1390
|
this.setDurationTimeCode();
|
|
2031
1391
|
}
|
|
2032
|
-
|
|
2033
|
-
this.videojs.el_.classList.remove('init');
|
|
1392
|
+
if (this.videojs.el_) this.videojs.el_.classList.remove('init');
|
|
2034
1393
|
};
|
|
2035
|
-
|
|
2036
|
-
// if video has not loaded by now, show the player w/ errors
|
|
2037
1394
|
setTimeout(() => {
|
|
2038
|
-
if (this.videojs.el_)
|
|
2039
|
-
this.videojs.el_.classList.remove('init');
|
|
2040
|
-
}
|
|
1395
|
+
if (this.videojs.el_) this.videojs.el_.classList.remove('init');
|
|
2041
1396
|
}, 2000);
|
|
2042
|
-
|
|
2043
|
-
// attach subtitle tracks (these should come in last in the <video /> node)
|
|
2044
1397
|
if (this.props.subtitles) {
|
|
2045
|
-
this.props.subtitles.forEach(
|
|
1398
|
+
this.props.subtitles.forEach(sub => {
|
|
2046
1399
|
const subtitleTag = document.createElement('track');
|
|
2047
1400
|
subtitleTag.kind = 'subtitles';
|
|
2048
1401
|
subtitleTag.srclang = sub.lang;
|
|
2049
1402
|
subtitleTag.label = sub.label;
|
|
2050
|
-
// subtitleTag.default = (index === 0) //can use this later to set a default track
|
|
2051
|
-
|
|
2052
1403
|
if (typeof sub.src === 'string') {
|
|
2053
|
-
subtitleTag.src = sub.src;
|
|
1404
|
+
subtitleTag.src = sub.src;
|
|
2054
1405
|
} else {
|
|
2055
|
-
subtitleTag.src = window.URL.createObjectURL(sub.src);
|
|
1406
|
+
subtitleTag.src = window.URL.createObjectURL(sub.src);
|
|
2056
1407
|
}
|
|
2057
|
-
|
|
2058
1408
|
this.videoEl.appendChild(subtitleTag);
|
|
2059
1409
|
});
|
|
2060
1410
|
}
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
this.props.target && this.props.target.appendChild(this.videoEl);
|
|
2065
|
-
}
|
|
2066
|
-
|
|
2067
|
-
const showDefaultTimeDisplay = (this.props.timecode !== true);
|
|
2068
|
-
const controlsEnabled = (this.props.controls !== false);
|
|
1411
|
+
if (this.props.target) this.props.target.appendChild(this.videoEl);
|
|
1412
|
+
const showDefaultTimeDisplay = this.props.timecode !== true;
|
|
1413
|
+
const controlsEnabled = this.props.controls !== false;
|
|
2069
1414
|
const options = this.props.options || {};
|
|
2070
|
-
|
|
2071
|
-
this.videojs = new videojs__default["default"]('vdt-video', {
|
|
1415
|
+
this.videojs = new videojs__default["default"]('vdt-video', _objectSpread({
|
|
2072
1416
|
responsive: true,
|
|
2073
1417
|
fluid: true,
|
|
2074
1418
|
controls: controlsEnabled,
|
|
2075
1419
|
alwaysCaptureHotkeys: false,
|
|
2076
1420
|
controlBar: {
|
|
2077
1421
|
RemainingTimeDisplay: false,
|
|
2078
|
-
timeDivider: showDefaultTimeDisplay,
|
|
1422
|
+
timeDivider: showDefaultTimeDisplay,
|
|
2079
1423
|
durationDisplay: showDefaultTimeDisplay,
|
|
2080
|
-
currentTimeDisplay: showDefaultTimeDisplay
|
|
1424
|
+
currentTimeDisplay: showDefaultTimeDisplay
|
|
2081
1425
|
},
|
|
2082
|
-
inactivityTimeout:
|
|
1426
|
+
inactivityTimeout: this.audioOnly ? constants$2.defaults.audioInactivityTimeout : constants$2.defaults.inactivityTimeout,
|
|
2083
1427
|
preload: 'auto',
|
|
2084
1428
|
captionsButton: false,
|
|
2085
1429
|
subsCapsButton: false,
|
|
2086
1430
|
subtitlesButton: false,
|
|
2087
1431
|
textTrackSettings: false,
|
|
2088
1432
|
html5: {
|
|
2089
|
-
nativeTextTracks: false
|
|
1433
|
+
nativeTextTracks: false
|
|
2090
1434
|
},
|
|
2091
1435
|
languages: {
|
|
2092
1436
|
en: {
|
|
2093
1437
|
'captions off': 'off',
|
|
2094
|
-
'subtitles off': 'off'
|
|
2095
|
-
}
|
|
2096
|
-
}
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
// set the poster
|
|
2101
|
-
this.props.posterUrl && this.videojs.poster(this.props.posterUrl);
|
|
2102
|
-
|
|
2103
|
-
// set other props that are passed
|
|
1438
|
+
'subtitles off': 'off'
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1441
|
+
}, options));
|
|
1442
|
+
if (this.props.posterUrl) this.videojs.poster(this.props.posterUrl);
|
|
2104
1443
|
this.handleNewProps(this.props);
|
|
2105
|
-
|
|
2106
|
-
// lifecycle
|
|
2107
1444
|
this.videojs.ready(() => {
|
|
2108
1445
|
this.bindHotkeys();
|
|
2109
1446
|
this.bindEvents();
|
|
2110
|
-
this.props.onReady
|
|
2111
|
-
|
|
1447
|
+
if (this.props.onReady) this.props.onReady(this.videojs);
|
|
2112
1448
|
this.restoreSettings();
|
|
2113
1449
|
this.setupTimeCode();
|
|
2114
1450
|
this.doEsothericWork();
|
|
@@ -2116,241 +1452,197 @@
|
|
|
2116
1452
|
this.setupCustomSeekbar();
|
|
2117
1453
|
});
|
|
2118
1454
|
}
|
|
2119
|
-
|
|
2120
1455
|
setupCustomSeekbar() {
|
|
2121
1456
|
if (this.props.seekBar) {
|
|
2122
|
-
// disable the built-in videojs seekbar
|
|
2123
1457
|
this.videojs.controlBar.progressControl.disable();
|
|
2124
1458
|
this.videojs.controlBar.progressControl.hide();
|
|
2125
|
-
|
|
2126
1459
|
const target = this.container.getElementsByClassName('vjs-control-bar')[0];
|
|
2127
|
-
const props = {
|
|
1460
|
+
const props = _objectSpread({
|
|
2128
1461
|
target,
|
|
2129
1462
|
player: this,
|
|
2130
|
-
onDark: this.props.onDark
|
|
2131
|
-
|
|
2132
|
-
};
|
|
2133
|
-
|
|
1463
|
+
onDark: this.props.onDark
|
|
1464
|
+
}, this.props.seekBar);
|
|
2134
1465
|
this.seekBar = new SeekBar(props);
|
|
2135
|
-
|
|
2136
|
-
// show & hide markers when controls hide
|
|
2137
1466
|
this.videojs.on('userinactive', () => {
|
|
2138
1467
|
if (!this.controlsBelowPlayer) {
|
|
2139
|
-
|
|
1468
|
+
var _this$seekBar$hideMar, _this$seekBar;
|
|
1469
|
+
if (this.seekBar) (_this$seekBar$hideMar = (_this$seekBar = this.seekBar).hideMarkers) === null || _this$seekBar$hideMar === void 0 ? void 0 : _this$seekBar$hideMar.call(_this$seekBar);
|
|
2140
1470
|
} else {
|
|
2141
|
-
|
|
1471
|
+
var _this$seekBar2, _this$seekBar2$showMa;
|
|
1472
|
+
(_this$seekBar2 = this.seekBar) === null || _this$seekBar2 === void 0 ? void 0 : (_this$seekBar2$showMa = _this$seekBar2.showMarkers) === null || _this$seekBar2$showMa === void 0 ? void 0 : _this$seekBar2$showMa.call(_this$seekBar2);
|
|
2142
1473
|
}
|
|
2143
1474
|
});
|
|
2144
|
-
|
|
2145
1475
|
this.videojs.on('useractive', () => {
|
|
2146
|
-
this.seekBar
|
|
1476
|
+
if (this.seekBar) this.seekBar.showMarkers();
|
|
2147
1477
|
});
|
|
2148
1478
|
}
|
|
2149
1479
|
}
|
|
2150
|
-
|
|
2151
|
-
|
|
1480
|
+
setupTimeCode() {
|
|
1481
|
+
let externalTimecodeInstance = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
|
|
2152
1482
|
const props = {
|
|
2153
1483
|
onInput: (e, nodeName, values) => {
|
|
2154
|
-
// TODO - check for out of bounds input
|
|
2155
1484
|
this.seekTo(this.timeConverter.smpteToCurrentTimeFromStart(values));
|
|
2156
1485
|
},
|
|
2157
1486
|
onInputFocus: () => {
|
|
2158
|
-
/*
|
|
2159
|
-
lock the control control bar in place to
|
|
2160
|
-
prevent it from unexpectedly animating away while
|
|
2161
|
-
doing timecode input
|
|
2162
|
-
*/
|
|
2163
1487
|
this.videojs.options_.inactivityTimeout = 0;
|
|
2164
1488
|
this.videojs.cache_.inactivityTimeout = 0;
|
|
2165
1489
|
this.videojs.reportUserActivity();
|
|
2166
|
-
|
|
2167
|
-
// pause the video, expected behaviour when editing timecode position
|
|
2168
1490
|
this.videojs.pause();
|
|
2169
1491
|
},
|
|
2170
1492
|
onInputBlur: () => {
|
|
2171
1493
|
this.videojs.options().inactivityTimeout = constants$2.defaults.inactivityTimeout;
|
|
2172
1494
|
this.videojs.cache_.inactivityTimeout = constants$2.defaults.inactivityTimeout;
|
|
2173
|
-
}
|
|
1495
|
+
}
|
|
2174
1496
|
};
|
|
2175
|
-
|
|
2176
|
-
if (externalTimecodeInstance !== null) { // setting up an external playback timecode
|
|
1497
|
+
if (externalTimecodeInstance !== null) {
|
|
2177
1498
|
externalTimecodeInstance.props = Object.assign(externalTimecodeInstance.props, props);
|
|
2178
1499
|
this.externalTimecodes.playback.push(externalTimecodeInstance);
|
|
2179
|
-
} else if (this.props.timecode === true) {
|
|
2180
|
-
// construct an in-frame timecode, if controls are enabled
|
|
1500
|
+
} else if (this.props.timecode === true) {
|
|
2181
1501
|
if (this.props.controls !== false) {
|
|
2182
1502
|
const target = document.getElementsByClassName('vjs-volume-panel')[0];
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
1503
|
+
this.timeCode = new TimeCodeDisplay(Object.assign(props, {
|
|
1504
|
+
target,
|
|
1505
|
+
appendAfter: true
|
|
1506
|
+
}));
|
|
2187
1507
|
this.durationTimeCode = new TimeCodeDisplay({
|
|
2188
1508
|
target: this.timeCode.container,
|
|
2189
|
-
appendAfter: true
|
|
1509
|
+
appendAfter: true
|
|
2190
1510
|
});
|
|
2191
1511
|
}
|
|
2192
1512
|
}
|
|
2193
|
-
|
|
2194
1513
|
if (this.timeCode || this.externalTimecodes.playback.length > 0) {
|
|
2195
|
-
// subscribe to events
|
|
2196
1514
|
this.videojs.on('timeupdate', () => {
|
|
2197
1515
|
this.updateTimeCode();
|
|
2198
1516
|
});
|
|
2199
|
-
|
|
2200
1517
|
this.videojs.on('play', () => {
|
|
2201
1518
|
this.updateTimeCodeFrame();
|
|
2202
1519
|
});
|
|
2203
1520
|
}
|
|
2204
1521
|
}
|
|
2205
|
-
|
|
2206
|
-
updateTimeCode() { // HH:MM:SS (the usual)
|
|
1522
|
+
updateTimeCode() {
|
|
2207
1523
|
const currentSecond = this.videojs.currentTime();
|
|
2208
1524
|
const props = this.timeConverter.secondsFromStartToSMPTE(currentSecond);
|
|
2209
|
-
|
|
2210
|
-
this.timeCode && this.timeCode.update(props);
|
|
2211
|
-
|
|
1525
|
+
if (this.timeCode) this.timeCode.update(props);
|
|
2212
1526
|
if (this.externalTimecodes.playback.length > 0) {
|
|
2213
|
-
this.externalTimecodes.playback.forEach(
|
|
1527
|
+
this.externalTimecodes.playback.forEach(timecode => {
|
|
2214
1528
|
timecode.update(props);
|
|
2215
1529
|
});
|
|
2216
1530
|
}
|
|
2217
1531
|
}
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
1532
|
+
updateTimeCodeFrame() {
|
|
1533
|
+
const frame = this.timeConverter.currentFrame(this.videojs.currentTime());
|
|
1534
|
+
if (this.timeCode) this.timeCode.update({
|
|
1535
|
+
frame
|
|
1536
|
+
});
|
|
2224
1537
|
if (this.externalTimecodes.playback.length > 0) {
|
|
2225
|
-
this.externalTimecodes.playback.forEach(
|
|
2226
|
-
timecode.update({
|
|
1538
|
+
this.externalTimecodes.playback.forEach(timecode => {
|
|
1539
|
+
timecode.update({
|
|
1540
|
+
frame
|
|
1541
|
+
});
|
|
2227
1542
|
});
|
|
2228
1543
|
}
|
|
2229
|
-
|
|
2230
|
-
// recursive invocation if still playing
|
|
2231
1544
|
if (!this.videojs.paused()) {
|
|
2232
|
-
this.rafID = requestAnimationFrame(() => {
|
|
1545
|
+
this.rafID = requestAnimationFrame(() => {
|
|
1546
|
+
this.updateTimeCodeFrame();
|
|
1547
|
+
});
|
|
2233
1548
|
}
|
|
2234
1549
|
}
|
|
2235
|
-
|
|
2236
|
-
setDurationTimeCode() { // happens once
|
|
1550
|
+
setDurationTimeCode() {
|
|
2237
1551
|
const durationInSeconds = this.videojs.duration();
|
|
2238
1552
|
const props = this.timeConverter.secondsFromStartToSMPTE(durationInSeconds);
|
|
2239
1553
|
props.frame = this.timeConverter.secondsToFrame(durationInSeconds);
|
|
2240
|
-
|
|
2241
1554
|
this.durationTimeCode.update(props);
|
|
2242
1555
|
this.durationTimeCode.container.classList.add('duration');
|
|
2243
1556
|
}
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
{
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
}
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
{
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
}
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
},
|
|
2305
|
-
{
|
|
2306
|
-
key: 'h',
|
|
2307
|
-
method: () => {
|
|
2308
|
-
this.help.toggle();
|
|
2309
|
-
},
|
|
2310
|
-
},
|
|
2311
|
-
{
|
|
2312
|
-
key: 'n',
|
|
2313
|
-
method: () => {
|
|
2314
|
-
this.menu && this.menu.toggle();
|
|
2315
|
-
},
|
|
2316
|
-
},
|
|
2317
|
-
];
|
|
2318
|
-
|
|
1557
|
+
bindHotkeys() {
|
|
1558
|
+
this.bindings = [{
|
|
1559
|
+
key: ['space', 'k'],
|
|
1560
|
+
method: e => {
|
|
1561
|
+
if (e.preventDefault) e.preventDefault();
|
|
1562
|
+
this.togglePlayback();
|
|
1563
|
+
}
|
|
1564
|
+
}, {
|
|
1565
|
+
key: 'j',
|
|
1566
|
+
method: () => {
|
|
1567
|
+
if (this.videojs.hasStarted_) this.jumpBackward();
|
|
1568
|
+
}
|
|
1569
|
+
}, {
|
|
1570
|
+
key: 'l',
|
|
1571
|
+
method: () => {
|
|
1572
|
+
if (this.videojs.hasStarted_) this.jumpForward();
|
|
1573
|
+
}
|
|
1574
|
+
}, {
|
|
1575
|
+
key: ['.', 'right'],
|
|
1576
|
+
method: () => {
|
|
1577
|
+
this.frameForward();
|
|
1578
|
+
}
|
|
1579
|
+
}, {
|
|
1580
|
+
key: [',', 'left'],
|
|
1581
|
+
method: () => {
|
|
1582
|
+
this.frameBackward();
|
|
1583
|
+
}
|
|
1584
|
+
}, {
|
|
1585
|
+
key: 'f',
|
|
1586
|
+
method: () => {
|
|
1587
|
+
this.toggleFullscreen();
|
|
1588
|
+
}
|
|
1589
|
+
}, {
|
|
1590
|
+
key: 'm',
|
|
1591
|
+
method: () => {
|
|
1592
|
+
this.toggleMute();
|
|
1593
|
+
}
|
|
1594
|
+
}, {
|
|
1595
|
+
key: 'up',
|
|
1596
|
+
method: e => {
|
|
1597
|
+
if (e.preventDefault) e.preventDefault();
|
|
1598
|
+
this.volumeUp();
|
|
1599
|
+
}
|
|
1600
|
+
}, {
|
|
1601
|
+
key: 'down',
|
|
1602
|
+
method: e => {
|
|
1603
|
+
if (e.preventDefault) e.preventDefault();
|
|
1604
|
+
this.volumeDown();
|
|
1605
|
+
}
|
|
1606
|
+
}, {
|
|
1607
|
+
key: 'h',
|
|
1608
|
+
method: () => {
|
|
1609
|
+
this.help.toggle();
|
|
1610
|
+
}
|
|
1611
|
+
}, {
|
|
1612
|
+
key: 'n',
|
|
1613
|
+
method: () => {
|
|
1614
|
+
if (this.menu) this.menu.toggle();
|
|
1615
|
+
}
|
|
1616
|
+
}];
|
|
2319
1617
|
if (this.props.subtitles) {
|
|
2320
1618
|
this.bindings.push({
|
|
2321
1619
|
key: 'c',
|
|
2322
1620
|
method: () => {
|
|
2323
1621
|
this.toggleSubs();
|
|
2324
|
-
}
|
|
1622
|
+
}
|
|
2325
1623
|
});
|
|
2326
1624
|
}
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
this.bindings.forEach((binding) => {
|
|
2330
|
-
mousetrap__default["default"].bind(binding.key, (e) => {
|
|
1625
|
+
this.bindings.forEach(binding => {
|
|
1626
|
+
mousetrap__default["default"].bind(binding.key, e => {
|
|
2331
1627
|
binding.method(e);
|
|
2332
1628
|
this.onHotkeyPressed(binding.key);
|
|
2333
1629
|
});
|
|
2334
1630
|
});
|
|
2335
1631
|
}
|
|
2336
|
-
|
|
2337
1632
|
unbindHotKeys() {
|
|
2338
|
-
this.bindings
|
|
1633
|
+
if (this.bindings) this.bindings.forEach(binding => {
|
|
2339
1634
|
mousetrap__default["default"].unbind(binding.key);
|
|
2340
1635
|
});
|
|
2341
1636
|
}
|
|
2342
|
-
|
|
2343
1637
|
bindEvents() {
|
|
2344
|
-
this.videojs.on('volumechange', () => {
|
|
1638
|
+
this.videojs.on('volumechange', () => {
|
|
2345
1639
|
this.persistSetting(constants$2.settings.volume, this.volume);
|
|
2346
1640
|
});
|
|
2347
|
-
|
|
2348
|
-
this.videojs.textTracks().on('change', () => { // determine subtitles state
|
|
1641
|
+
this.videojs.textTracks().on('change', () => {
|
|
2349
1642
|
const tracks = this.videojs.textTracks().tracks_;
|
|
2350
|
-
const selected = tracks.filter(
|
|
2351
|
-
const areAnyTxtTracksActive = selected.length > 0;
|
|
2352
|
-
|
|
2353
|
-
if (areAnyTxtTracksActive) { // update container with appropriate className
|
|
1643
|
+
const selected = tracks.filter(track => track.mode === 'showing');
|
|
1644
|
+
const areAnyTxtTracksActive = selected.length > 0;
|
|
1645
|
+
if (areAnyTxtTracksActive) {
|
|
2354
1646
|
this.videojs.el_.classList.add(constants$2.classNames.subtitlesActive);
|
|
2355
1647
|
this.persistSetting(constants$2.settings.subs, true);
|
|
2356
1648
|
this.persistSetting(constants$2.settings.subLang, selected[0].language);
|
|
@@ -2360,27 +1652,31 @@
|
|
|
2360
1652
|
}
|
|
2361
1653
|
});
|
|
2362
1654
|
}
|
|
2363
|
-
|
|
2364
1655
|
volumeUp() {
|
|
2365
1656
|
this.videojs.controlBar.volumePanel.volumeControl.volumeBar.stepForward();
|
|
2366
|
-
this.osd.feedback(constants$2.osd.volchange, {
|
|
1657
|
+
this.osd.feedback(constants$2.osd.volchange, {
|
|
1658
|
+
volume: this.volume
|
|
1659
|
+
});
|
|
2367
1660
|
}
|
|
2368
|
-
|
|
2369
1661
|
volumeDown() {
|
|
2370
1662
|
this.videojs.controlBar.volumePanel.volumeControl.volumeBar.stepBack();
|
|
2371
|
-
this.osd.feedback(constants$2.osd.volchange, {
|
|
1663
|
+
this.osd.feedback(constants$2.osd.volchange, {
|
|
1664
|
+
volume: this.volume
|
|
1665
|
+
});
|
|
2372
1666
|
}
|
|
2373
|
-
|
|
2374
1667
|
toggleMute() {
|
|
2375
1668
|
if (!this.videojs.muted()) {
|
|
2376
1669
|
this.videojs.muted(true);
|
|
2377
|
-
this.osd.feedback(constants$2.osd.volchange, {
|
|
1670
|
+
this.osd.feedback(constants$2.osd.volchange, {
|
|
1671
|
+
volume: this.volume
|
|
1672
|
+
});
|
|
2378
1673
|
} else {
|
|
2379
1674
|
this.videojs.muted(false);
|
|
2380
|
-
this.osd.feedback(constants$2.osd.volchange, {
|
|
1675
|
+
this.osd.feedback(constants$2.osd.volchange, {
|
|
1676
|
+
volume: this.volume
|
|
1677
|
+
});
|
|
2381
1678
|
}
|
|
2382
1679
|
}
|
|
2383
|
-
|
|
2384
1680
|
toggleFullscreen() {
|
|
2385
1681
|
if (this.videojs.isFullscreen()) {
|
|
2386
1682
|
this.videojs.exitFullscreen();
|
|
@@ -2388,68 +1684,51 @@
|
|
|
2388
1684
|
this.videojs.requestFullscreen();
|
|
2389
1685
|
}
|
|
2390
1686
|
}
|
|
2391
|
-
|
|
2392
|
-
seek(secs) { // relative to current playback time
|
|
1687
|
+
seek(secs) {
|
|
2393
1688
|
let time = this.videojs.currentTime() + secs;
|
|
2394
|
-
|
|
2395
1689
|
if (time < 0) {
|
|
2396
1690
|
time = 0;
|
|
2397
1691
|
}
|
|
2398
|
-
|
|
2399
1692
|
this.videojs.currentTime(time);
|
|
2400
1693
|
}
|
|
2401
|
-
|
|
2402
1694
|
seekTo(sec) {
|
|
2403
|
-
!this.videojs.hasStarted()
|
|
1695
|
+
if (!this.videojs.hasStarted()) this.videojs.hasStarted(true);
|
|
2404
1696
|
this.videojs.currentTime(sec);
|
|
2405
1697
|
}
|
|
2406
|
-
|
|
2407
1698
|
jumpForward() {
|
|
2408
1699
|
this.seek(constants$2.defaults.jumpSeconds);
|
|
2409
1700
|
this.osd.feedback(constants$2.osd.jumpForward);
|
|
2410
1701
|
}
|
|
2411
|
-
|
|
2412
1702
|
jumpBackward() {
|
|
2413
1703
|
this.seek(-constants$2.defaults.jumpSeconds);
|
|
2414
1704
|
this.osd.feedback(constants$2.osd.jumpBackward);
|
|
2415
1705
|
}
|
|
2416
|
-
|
|
2417
1706
|
frameForward() {
|
|
2418
1707
|
const thisFrame = this.timeConverter.secondsToFramesFromStart(this.videojs.currentTime());
|
|
2419
1708
|
const nextFrame = Math.round(thisFrame) + 1;
|
|
2420
|
-
|
|
2421
1709
|
this.videojs.currentTime(this.timeConverter.frameToCurrentTimeFromStart(nextFrame));
|
|
2422
1710
|
}
|
|
2423
|
-
|
|
2424
1711
|
frameBackward() {
|
|
2425
1712
|
const thisFrame = this.timeConverter.secondsToFramesFromStart(this.videojs.currentTime());
|
|
2426
1713
|
const previousFrame = Math.round(thisFrame) - 1;
|
|
2427
|
-
|
|
2428
1714
|
this.videojs.currentTime(this.timeConverter.frameToCurrentTimeFromStart(previousFrame));
|
|
2429
1715
|
}
|
|
2430
|
-
|
|
2431
1716
|
secondsToFramesFromStart(seconds) {
|
|
2432
1717
|
const frameRate = this.props.frameRate || constants$2.defaults.frameRate;
|
|
2433
1718
|
let frame = seconds * frameRate;
|
|
2434
1719
|
frame = Math.round(frame);
|
|
2435
|
-
return frame;
|
|
1720
|
+
return frame;
|
|
2436
1721
|
}
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
if (this.props.color) { // change the seekbar color from props
|
|
1722
|
+
doEsothericWork() {
|
|
1723
|
+
if (this.props.color) {
|
|
2440
1724
|
document.getElementsByClassName('vjs-play-progress')[0].style.backgroundColor = this.props.color;
|
|
2441
1725
|
}
|
|
2442
|
-
|
|
2443
|
-
// feedback gizmo, mainly for feedback on hotkey-presses
|
|
2444
1726
|
this.osd = new OSD({
|
|
2445
|
-
target: this.videoEl.parentElement
|
|
1727
|
+
target: this.videoEl.parentElement
|
|
2446
1728
|
});
|
|
2447
|
-
|
|
2448
|
-
// add a cinema button if a callback is passed in props
|
|
2449
1729
|
if (this.props.onCinema) {
|
|
2450
1730
|
this.videoEl.parentElement.classList.add('has-cinema-button');
|
|
2451
1731
|
this.cinema = false;
|
|
2452
|
-
|
|
2453
1732
|
this.addButtonToControlBar({
|
|
2454
1733
|
onClick: () => {
|
|
2455
1734
|
this.props.onCinema(!this.cinema);
|
|
@@ -2457,28 +1736,23 @@
|
|
|
2457
1736
|
},
|
|
2458
1737
|
componentName: 'CinemaButton',
|
|
2459
1738
|
className: 'vdt-cinema-button',
|
|
2460
|
-
title: 'Cinema-mode'
|
|
1739
|
+
title: 'Cinema-mode'
|
|
2461
1740
|
});
|
|
2462
1741
|
}
|
|
2463
|
-
|
|
2464
|
-
// add a screenshot button if a callback is passed in props
|
|
2465
1742
|
if (this.props.onScreenshot) {
|
|
2466
1743
|
this.videoEl.parentElement.classList.add('has-screenshot-button');
|
|
2467
|
-
|
|
2468
1744
|
this.addButtonToControlBar({
|
|
2469
1745
|
onClick: () => {
|
|
2470
1746
|
this.props.onScreenshot(this.videojs.currentTime());
|
|
2471
1747
|
},
|
|
2472
1748
|
componentName: 'ScreenshotButton',
|
|
2473
1749
|
className: 'vdt-screenshot-button',
|
|
2474
|
-
title: 'Screenshot'
|
|
1750
|
+
title: 'Screenshot'
|
|
2475
1751
|
});
|
|
2476
1752
|
}
|
|
2477
|
-
|
|
2478
|
-
// add a help overlay explaining keyboard controls
|
|
2479
1753
|
this.help = new HelpOverlay({
|
|
2480
1754
|
target: this.videoEl.parentElement,
|
|
2481
|
-
onToggle:
|
|
1755
|
+
onToggle: willShow => {
|
|
2482
1756
|
if (this.menu && this.menu.opened) {
|
|
2483
1757
|
this.menu.close();
|
|
2484
1758
|
}
|
|
@@ -2487,41 +1761,30 @@
|
|
|
2487
1761
|
} else {
|
|
2488
1762
|
this.showControls();
|
|
2489
1763
|
}
|
|
2490
|
-
}
|
|
1764
|
+
}
|
|
2491
1765
|
});
|
|
2492
1766
|
}
|
|
2493
|
-
|
|
2494
|
-
restoreSettings() { // restore settings, like volume level or language track
|
|
2495
|
-
// get values from storage
|
|
1767
|
+
restoreSettings() {
|
|
2496
1768
|
const volume = localStorage.getItem(constants$2.settings.volume);
|
|
2497
1769
|
const subsEnabled = localStorage.getItem(constants$2.settings.subs);
|
|
2498
1770
|
const subLang = localStorage.getItem(constants$2.settings.subLang);
|
|
2499
|
-
|
|
2500
|
-
// values vs default behaviours in a neatly readable map
|
|
2501
1771
|
this.settings = {
|
|
2502
|
-
|
|
2503
|
-
[constants$2.settings.
|
|
2504
|
-
[constants$2.settings.
|
|
2505
|
-
[constants$2.settings.subs]: (subsEnabled !== null) ? JSON.parse(subsEnabled) : false,
|
|
1772
|
+
[constants$2.settings.volume]: volume !== null ? Math.round(volume * 100) / 100 : 1,
|
|
1773
|
+
[constants$2.settings.subLang]: subLang !== null ? subLang : 'en',
|
|
1774
|
+
[constants$2.settings.subs]: subsEnabled !== null ? JSON.parse(subsEnabled) : false
|
|
2506
1775
|
};
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
this.volume = this.settings[constants$2.settings.volume]; // volume
|
|
2510
|
-
|
|
2511
|
-
if (this.settings[constants$2.settings.subs]) { // subtitles
|
|
1776
|
+
this.volume = this.settings[constants$2.settings.volume];
|
|
1777
|
+
if (this.settings[constants$2.settings.subs]) {
|
|
2512
1778
|
this.enableSubs();
|
|
2513
1779
|
}
|
|
2514
1780
|
}
|
|
2515
|
-
|
|
2516
1781
|
persistSetting(key, val) {
|
|
2517
1782
|
this.settings[key] = val;
|
|
2518
1783
|
localStorage.setItem(key, val);
|
|
2519
1784
|
}
|
|
2520
|
-
|
|
2521
1785
|
enableSubs() {
|
|
2522
1786
|
const subs = this.videojs.textTracks();
|
|
2523
|
-
|
|
2524
|
-
for (let i = 0; i < subs.length; i++) {
|
|
1787
|
+
for (let i = 0; i < subs.length; i += 1) {
|
|
2525
1788
|
const sub = subs[i];
|
|
2526
1789
|
if (sub.language === this.settings[constants$2.settings.subLang]) {
|
|
2527
1790
|
sub.mode = 'showing';
|
|
@@ -2530,57 +1793,42 @@
|
|
|
2530
1793
|
}
|
|
2531
1794
|
}
|
|
2532
1795
|
}
|
|
2533
|
-
|
|
2534
1796
|
disableSubs() {
|
|
2535
1797
|
const subs = this.videojs.textTracks();
|
|
2536
|
-
|
|
2537
|
-
for (let i = 0; i < subs.length; i++) {
|
|
1798
|
+
for (let i = 0; i < subs.length; i += 1) {
|
|
2538
1799
|
const sub = subs[i];
|
|
2539
1800
|
sub.mode = 'hidden';
|
|
2540
1801
|
}
|
|
2541
1802
|
}
|
|
2542
|
-
|
|
2543
1803
|
toggleSubs() {
|
|
2544
|
-
if (this.videojs.textTracks().length > 0) {
|
|
2545
|
-
if (this.videojs.textTracks().tracks_.filter(
|
|
1804
|
+
if (this.videojs.textTracks().length > 0) {
|
|
1805
|
+
if (this.videojs.textTracks().tracks_.filter(track => track.mode === 'showing').length > 0) {
|
|
2546
1806
|
this.disableSubs();
|
|
2547
1807
|
} else {
|
|
2548
1808
|
this.enableSubs();
|
|
2549
1809
|
}
|
|
2550
1810
|
}
|
|
2551
1811
|
}
|
|
2552
|
-
|
|
2553
|
-
/*
|
|
2554
|
-
A quick example
|
|
2555
|
-
options = {
|
|
2556
|
-
onClick: ()=>{},
|
|
2557
|
-
componentName: 'ScreenshotButton',
|
|
2558
|
-
className: 'vdt-screenshot-button'
|
|
2559
|
-
}
|
|
2560
|
-
*/
|
|
2561
1812
|
addButtonToControlBar(options) {
|
|
2562
1813
|
const Button = videojs__default["default"].getComponent('Button');
|
|
2563
1814
|
const CustomButton = videojs__default["default"].extend(Button, {
|
|
2564
|
-
|
|
2565
|
-
constructor: function () {
|
|
1815
|
+
constructor: function constructor() {
|
|
2566
1816
|
Button.apply(this, arguments);
|
|
2567
|
-
options.className
|
|
2568
|
-
if (options.title) {
|
|
1817
|
+
if (options.className) this.el_.classList.add(options.className);
|
|
1818
|
+
if (options.title) {
|
|
1819
|
+
this.el_.title = options.title;
|
|
1820
|
+
}
|
|
2569
1821
|
},
|
|
2570
1822
|
handleClick: () => {
|
|
2571
|
-
options.onClick
|
|
2572
|
-
}
|
|
1823
|
+
if (options.onClick) options.onClick();
|
|
1824
|
+
}
|
|
2573
1825
|
});
|
|
2574
|
-
|
|
2575
1826
|
videojs__default["default"].registerComponent(options.componentName, CustomButton);
|
|
2576
1827
|
this.videojs.getChild('controlBar').addChild(options.componentName, {}, 7);
|
|
2577
1828
|
}
|
|
2578
|
-
|
|
2579
|
-
// convenient getters / setters
|
|
2580
1829
|
get volume() {
|
|
2581
1830
|
return this.videojs.controlBar.volumePanel.volumeControl.volumeBar.getPercent();
|
|
2582
1831
|
}
|
|
2583
|
-
|
|
2584
1832
|
set volume(floatVal) {
|
|
2585
1833
|
if (floatVal === 0) {
|
|
2586
1834
|
this.videojs.muted(true);
|
|
@@ -2589,58 +1837,42 @@
|
|
|
2589
1837
|
this.videojs.volume(floatVal);
|
|
2590
1838
|
}
|
|
2591
1839
|
}
|
|
2592
|
-
|
|
2593
1840
|
setupMenu() {
|
|
2594
1841
|
const menuItems = this.props.menuItems || [];
|
|
2595
1842
|
const sourcesMenuItems = [];
|
|
2596
|
-
if (this.props.sources.length > 1) {
|
|
2597
|
-
this.props.sources.forEach(
|
|
1843
|
+
if (this.props.sources.length > 1) {
|
|
1844
|
+
this.props.sources.forEach(source => {
|
|
2598
1845
|
if (source.label) {
|
|
2599
1846
|
sourcesMenuItems.push({
|
|
2600
1847
|
title: source.label,
|
|
2601
1848
|
onClick: () => {
|
|
2602
1849
|
this.src = source;
|
|
2603
|
-
}
|
|
1850
|
+
}
|
|
2604
1851
|
});
|
|
2605
1852
|
}
|
|
2606
1853
|
});
|
|
2607
|
-
|
|
2608
1854
|
menuItems.push({
|
|
2609
1855
|
title: 'Sources',
|
|
2610
1856
|
getActiveIndex: () => {
|
|
2611
|
-
const matchingSource = this.props.sources.find(
|
|
2612
|
-
return sourcesMenuItems.indexOf(sourcesMenuItems.find(
|
|
1857
|
+
const matchingSource = this.props.sources.find(source => source.src === this.videojs.src());
|
|
1858
|
+
return sourcesMenuItems.indexOf(sourcesMenuItems.find(menuItem => menuItem.title === matchingSource.label));
|
|
2613
1859
|
},
|
|
2614
|
-
items: sourcesMenuItems
|
|
1860
|
+
items: sourcesMenuItems
|
|
2615
1861
|
});
|
|
2616
1862
|
}
|
|
2617
|
-
|
|
2618
|
-
// subtitles
|
|
2619
1863
|
if (this.props.subtitles && this.props.subtitles.length > 0) {
|
|
2620
|
-
// off option for subs
|
|
2621
1864
|
const subtitleMenuItems = [{
|
|
2622
1865
|
title: 'Off',
|
|
2623
1866
|
onClick: () => {
|
|
2624
1867
|
this.disableSubs();
|
|
2625
|
-
}
|
|
1868
|
+
}
|
|
2626
1869
|
}];
|
|
2627
|
-
|
|
2628
|
-
// quick toggle in the control bar
|
|
2629
|
-
// this.addButtonToControlBar({
|
|
2630
|
-
// onClick: () => {
|
|
2631
|
-
// this.props.onCinema(!this.cinema);
|
|
2632
|
-
// this.cinema = !this.cinema;
|
|
2633
|
-
// },
|
|
2634
|
-
// componentName: 'CinemaButton',
|
|
2635
|
-
// className: 'vdt-cinema-button',
|
|
2636
|
-
// });
|
|
2637
|
-
|
|
2638
1870
|
this.props.subtitles.forEach((subtitle, index) => {
|
|
2639
1871
|
subtitleMenuItems.push({
|
|
2640
1872
|
title: subtitle.label,
|
|
2641
1873
|
onClick: () => {
|
|
2642
1874
|
const subs = this.videojs.textTracks();
|
|
2643
|
-
for (let i = 0; i < subs.length; i
|
|
1875
|
+
for (let i = 0; i < subs.length; i += 1) {
|
|
2644
1876
|
const sub = subs[i];
|
|
2645
1877
|
if (i === index) {
|
|
2646
1878
|
sub.mode = 'showing';
|
|
@@ -2648,72 +1880,59 @@
|
|
|
2648
1880
|
sub.mode = 'hidden';
|
|
2649
1881
|
}
|
|
2650
1882
|
}
|
|
2651
|
-
}
|
|
1883
|
+
}
|
|
2652
1884
|
});
|
|
2653
1885
|
});
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
{
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
const
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
if (sub.mode === 'showing') {
|
|
2663
|
-
return i + 1; // offset "off" option
|
|
2664
|
-
}
|
|
1886
|
+
menuItems.push({
|
|
1887
|
+
title: 'Subtitles',
|
|
1888
|
+
getActiveIndex: () => {
|
|
1889
|
+
const subs = this.videojs.textTracks();
|
|
1890
|
+
for (let i = 0; i < subs.length; i += 1) {
|
|
1891
|
+
const sub = subs[i];
|
|
1892
|
+
if (sub.mode === 'showing') {
|
|
1893
|
+
return i + 1;
|
|
2665
1894
|
}
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
},
|
|
2669
|
-
items: subtitleMenuItems,
|
|
1895
|
+
}
|
|
1896
|
+
return 0;
|
|
2670
1897
|
},
|
|
2671
|
-
|
|
1898
|
+
items: subtitleMenuItems
|
|
1899
|
+
});
|
|
2672
1900
|
}
|
|
2673
|
-
|
|
2674
1901
|
if (menuItems.length > 0) {
|
|
2675
1902
|
const target = this.videojs.el_;
|
|
2676
|
-
|
|
2677
1903
|
this.menu = new Menu({
|
|
2678
1904
|
target,
|
|
2679
1905
|
items: menuItems,
|
|
2680
1906
|
onOpen: () => {
|
|
2681
|
-
!this.controlsBelowPlayer
|
|
1907
|
+
if (!this.controlsBelowPlayer) this.hideControls();
|
|
2682
1908
|
},
|
|
2683
1909
|
onClose: () => {
|
|
2684
|
-
!this.controlsBelowPlayer
|
|
2685
|
-
}
|
|
1910
|
+
if (!this.controlsBelowPlayer) this.videojs.controls(true);
|
|
1911
|
+
}
|
|
2686
1912
|
});
|
|
2687
|
-
|
|
2688
|
-
// add a cogwheel button to the player
|
|
2689
1913
|
this.videoEl.parentElement.classList.add('has-vdt-menu');
|
|
2690
|
-
|
|
2691
1914
|
this.addButtonToControlBar({
|
|
2692
1915
|
onClick: () => {
|
|
2693
1916
|
this.menu.toggle();
|
|
2694
1917
|
},
|
|
2695
1918
|
componentName: 'SettingsMenuButton',
|
|
2696
1919
|
className: 'vdt-settings-menu-button',
|
|
2697
|
-
title: 'Settings'
|
|
1920
|
+
title: 'Settings'
|
|
2698
1921
|
});
|
|
2699
1922
|
}
|
|
2700
1923
|
}
|
|
2701
|
-
|
|
2702
1924
|
hideControls() {
|
|
2703
1925
|
this.videojs.userActive(false);
|
|
2704
1926
|
this.videojs.controls(false);
|
|
2705
1927
|
this.videojs.fluid(true);
|
|
2706
|
-
|
|
2707
1928
|
this.videoEl.parentElement.classList.remove('vjs-user-active');
|
|
2708
1929
|
this.videojs.userActive(false);
|
|
2709
1930
|
}
|
|
2710
|
-
|
|
2711
1931
|
showControls() {
|
|
2712
1932
|
this.videojs.fluid(!this.controlsBelowPlayer);
|
|
2713
1933
|
this.videojs.controls(true);
|
|
2714
1934
|
this.videojs.userActive(true);
|
|
2715
1935
|
}
|
|
2716
|
-
|
|
2717
1936
|
toggleControls() {
|
|
2718
1937
|
if (this.videojs.controls()) {
|
|
2719
1938
|
this.hideControls();
|
|
@@ -2721,77 +1940,73 @@
|
|
|
2721
1940
|
this.showControls();
|
|
2722
1941
|
}
|
|
2723
1942
|
}
|
|
2724
|
-
|
|
2725
1943
|
onHotkeyPressed(key) {
|
|
2726
1944
|
if (key !== 'h' && this.help.state.active) {
|
|
2727
1945
|
this.help.hide();
|
|
2728
1946
|
}
|
|
2729
1947
|
}
|
|
2730
|
-
|
|
2731
|
-
// eslint-disable-next-line class-methods-use-this
|
|
2732
1948
|
triggerHotkey(key) {
|
|
2733
1949
|
mousetrap__default["default"].trigger(key);
|
|
2734
1950
|
}
|
|
2735
|
-
|
|
2736
1951
|
toStart() {
|
|
2737
1952
|
this.videojs.currentTime(0);
|
|
2738
1953
|
}
|
|
2739
|
-
|
|
2740
1954
|
toEnd() {
|
|
2741
1955
|
this.videojs.currentTime(this.videojs.duration());
|
|
2742
1956
|
}
|
|
2743
|
-
|
|
2744
1957
|
replay() {
|
|
2745
1958
|
this.toStart();
|
|
2746
1959
|
this.videojs.play();
|
|
2747
1960
|
}
|
|
2748
|
-
|
|
2749
1961
|
play() {
|
|
2750
1962
|
this.videojs.play();
|
|
2751
1963
|
}
|
|
2752
|
-
|
|
2753
1964
|
pause() {
|
|
2754
|
-
!this.videojs.paused()
|
|
1965
|
+
if (!this.videojs.paused()) this.videojs.pause();
|
|
2755
1966
|
}
|
|
2756
|
-
|
|
2757
1967
|
togglePlayback() {
|
|
2758
1968
|
if (this.videojs.paused()) {
|
|
2759
1969
|
this.play();
|
|
2760
|
-
this.videojs.hasStarted_
|
|
1970
|
+
if (this.videojs.hasStarted_) this.osd.feedback(constants$2.osd.play);
|
|
2761
1971
|
} else {
|
|
2762
1972
|
this.pause();
|
|
2763
1973
|
this.osd.feedback(constants$2.osd.pause);
|
|
2764
1974
|
}
|
|
2765
1975
|
}
|
|
2766
|
-
|
|
2767
|
-
|
|
1976
|
+
updateSmpte(valuesObj) {
|
|
1977
|
+
const startCount = this.nodeNames.length - 1;
|
|
1978
|
+
let i;
|
|
1979
|
+
for (i = startCount; i > -1; i -= 1) {
|
|
1980
|
+
const key = this.nodeNames[i];
|
|
1981
|
+
if (typeof valuesObj[key] !== 'undefined' && valuesObj[key] !== parseInt(this.nodes[key].value, 10) && key !== this.state.selectedNode) {
|
|
1982
|
+
const str = valuesObj[key].toString();
|
|
1983
|
+
this.nodes[key].value = this.toDigitPairStr(str);
|
|
1984
|
+
}
|
|
1985
|
+
}
|
|
1986
|
+
}
|
|
1987
|
+
destroy() {
|
|
2768
1988
|
this.videojs.paused(true);
|
|
2769
|
-
this.rafID
|
|
1989
|
+
if (this.rafID) cancelAnimationFrame(this.rafID);
|
|
2770
1990
|
this.videojs.dispose();
|
|
2771
1991
|
this.unbindHotKeys();
|
|
2772
|
-
this.seekBar
|
|
1992
|
+
if (this.seekBar) this.seekBar.destroy();
|
|
2773
1993
|
}
|
|
2774
|
-
|
|
2775
1994
|
get container() {
|
|
2776
1995
|
return this.videoEl.parentElement;
|
|
2777
1996
|
}
|
|
2778
|
-
|
|
2779
1997
|
set onDark(bool) {
|
|
2780
1998
|
if (bool) {
|
|
2781
1999
|
this.container.classList.add('on-dark');
|
|
2782
2000
|
} else {
|
|
2783
2001
|
this.container.classList.remove('on-dark');
|
|
2784
2002
|
}
|
|
2785
|
-
|
|
2786
2003
|
if (this.seekBar) {
|
|
2787
2004
|
this.seekBar.onDark = bool;
|
|
2788
2005
|
}
|
|
2789
2006
|
}
|
|
2790
|
-
|
|
2791
2007
|
get onDark() {
|
|
2792
2008
|
return this.container.classList.contains('on-dark');
|
|
2793
2009
|
}
|
|
2794
|
-
|
|
2795
2010
|
set controlsBelowPlayer(bool) {
|
|
2796
2011
|
if (this.videojs.controls()) {
|
|
2797
2012
|
if (bool) {
|
|
@@ -2803,36 +2018,29 @@
|
|
|
2803
2018
|
}
|
|
2804
2019
|
}
|
|
2805
2020
|
}
|
|
2806
|
-
|
|
2807
2021
|
get controlsBelowPlayer() {
|
|
2808
2022
|
return this.container.classList.contains('controls-below-player');
|
|
2809
2023
|
}
|
|
2810
|
-
|
|
2811
2024
|
get smpte() {
|
|
2812
2025
|
const currentSecond = this.videojs.currentTime();
|
|
2813
2026
|
return this.timeConverter.secondsFromStartToSMPTE(currentSecond);
|
|
2814
2027
|
}
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
const currentSecond = this.videojs.currentTime();
|
|
2818
|
-
return this.timeConverter.secondsFromStartToSMPTE(currentSecond);
|
|
2028
|
+
set smpte(o) {
|
|
2029
|
+
this.updateSmpte(o);
|
|
2819
2030
|
}
|
|
2820
|
-
|
|
2821
|
-
|
|
2031
|
+
set src(_ref) {
|
|
2032
|
+
let {
|
|
2033
|
+
src,
|
|
2034
|
+
type = 'video/mp4',
|
|
2035
|
+
label = null
|
|
2036
|
+
} = _ref;
|
|
2822
2037
|
const currentTime = this.videojs.currentTime();
|
|
2823
|
-
|
|
2824
|
-
const source = this.props.sources.find((aSource) => (aSource.src === src));
|
|
2825
|
-
// if no match try adding source
|
|
2826
|
-
|
|
2038
|
+
const source = this.props.sources.find(aSource => aSource.src === src);
|
|
2827
2039
|
const onReady = () => {
|
|
2828
2040
|
let initdone = false;
|
|
2829
|
-
// wait for video metadata to load, then set time
|
|
2830
2041
|
this.videojs.on('loadedmetadata', () => {
|
|
2831
2042
|
this.videojs.currentTime(currentTime);
|
|
2832
2043
|
});
|
|
2833
|
-
|
|
2834
|
-
// iPhone/iPad need to play first, then set the time
|
|
2835
|
-
// events: https://www.w3.org/TR/html5/embedded-content-0.html#mediaevents
|
|
2836
2044
|
this.videojs.on('canplaythrough', () => {
|
|
2837
2045
|
if (!initdone) {
|
|
2838
2046
|
this.videojs.currentTime(currentTime);
|
|
@@ -2841,13 +2049,9 @@
|
|
|
2841
2049
|
}
|
|
2842
2050
|
});
|
|
2843
2051
|
};
|
|
2844
|
-
|
|
2845
|
-
if (source && typeof souce === 'Array' && source.length > 0) {
|
|
2846
|
-
// TODO - if(source.length > 1) - try one by one until a successful load happens
|
|
2052
|
+
if (source && Array.isArray(source) && source.length > 0) {
|
|
2847
2053
|
this.videojs.addClass('vjs-waiting');
|
|
2848
|
-
this.videojs.src({
|
|
2849
|
-
...source[0],
|
|
2850
|
-
});
|
|
2054
|
+
this.videojs.src(_objectSpread({}, source[0]));
|
|
2851
2055
|
onReady();
|
|
2852
2056
|
} else {
|
|
2853
2057
|
this.videojs.addClass('vjs-waiting');
|
|
@@ -2855,26 +2059,20 @@
|
|
|
2855
2059
|
onReady();
|
|
2856
2060
|
}
|
|
2857
2061
|
}
|
|
2858
|
-
|
|
2859
2062
|
get src() {
|
|
2860
2063
|
return this.videojs.src();
|
|
2861
2064
|
}
|
|
2862
|
-
|
|
2863
2065
|
addSrc(src, type, label) {
|
|
2864
2066
|
const newSource = {
|
|
2865
2067
|
src,
|
|
2866
2068
|
type,
|
|
2867
|
-
label
|
|
2069
|
+
label
|
|
2868
2070
|
};
|
|
2869
2071
|
const index = this.props.sources.push(newSource) - 1;
|
|
2870
|
-
|
|
2871
2072
|
return this.props.sources[index];
|
|
2872
2073
|
}
|
|
2873
|
-
|
|
2874
2074
|
removeSrc(url) {
|
|
2875
|
-
// should remove all url matching sources
|
|
2876
2075
|
}
|
|
2877
|
-
|
|
2878
2076
|
set controls(bool) {
|
|
2879
2077
|
if (bool) {
|
|
2880
2078
|
this.showControls();
|
|
@@ -2882,357 +2080,30 @@
|
|
|
2882
2080
|
this.hideControls();
|
|
2883
2081
|
}
|
|
2884
2082
|
}
|
|
2885
|
-
|
|
2886
2083
|
get percentLoaded() {
|
|
2887
2084
|
const r = this.videojs.buffered();
|
|
2888
|
-
|
|
2889
|
-
const percentLoaded = (r.end(0) / this.videojs.duration()) * 100;
|
|
2085
|
+
const percentLoaded = r.end(0) / this.videojs.duration() * 100;
|
|
2890
2086
|
return percentLoaded;
|
|
2891
2087
|
}
|
|
2892
2088
|
}
|
|
2893
|
-
|
|
2894
|
-
/*
|
|
2895
|
-
Some video.js prototype overrides, that
|
|
2896
|
-
help with undesired behaviour
|
|
2897
|
-
*/
|
|
2898
|
-
|
|
2899
|
-
// take over space button, prevent video.js default behaviour
|
|
2900
2089
|
const button = videojs__default["default"].prototype.constructor.getComponent('Button');
|
|
2901
|
-
// eslint-disable-next-line func-names
|
|
2902
2090
|
button.prototype.handleKeyDown = function (e) {
|
|
2903
2091
|
if (e.keyCode === 32) {
|
|
2904
2092
|
e.preventDefault();
|
|
2905
2093
|
}
|
|
2906
2094
|
};
|
|
2907
2095
|
videojs__default["default"].prototype.constructor.registerComponent('Button', button);
|
|
2908
|
-
|
|
2909
|
-
// video.js opens menu on hover by default, this prevents that
|
|
2910
2096
|
const subsButton = videojs__default["default"].prototype.constructor.getComponent('SubsCapsButton');
|
|
2911
2097
|
class CustomSubsCapsButton extends subsButton {
|
|
2912
|
-
constructor(player
|
|
2098
|
+
constructor(player) {
|
|
2099
|
+
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
2913
2100
|
super(player, options);
|
|
2914
2101
|
this.menuButton_.off('mouseenter');
|
|
2915
2102
|
this.menuButton_.off('mouseleave');
|
|
2916
2103
|
}
|
|
2917
2104
|
}
|
|
2918
|
-
|
|
2919
|
-
/*
|
|
2920
|
-
TODO - see what can be done about strange behaviour
|
|
2921
|
-
when cc button is clicked with the menu showing
|
|
2922
|
-
*/
|
|
2923
2105
|
videojs__default["default"].prototype.constructor.registerComponent('SubsCapsButton', CustomSubsCapsButton);
|
|
2924
2106
|
|
|
2925
|
-
/* eslint-disable no-plusplus */
|
|
2926
|
-
|
|
2927
|
-
const buttonNames = Object.freeze({
|
|
2928
|
-
play: 'play-pause',
|
|
2929
|
-
start: 'start',
|
|
2930
|
-
fb: 'frame-backward',
|
|
2931
|
-
ff: 'frame-forward',
|
|
2932
|
-
end: 'end',
|
|
2933
|
-
});
|
|
2934
|
-
|
|
2935
|
-
const buttons = [ // order matters
|
|
2936
|
-
buttonNames.start,
|
|
2937
|
-
buttonNames.fb,
|
|
2938
|
-
buttonNames.play,
|
|
2939
|
-
buttonNames.ff,
|
|
2940
|
-
buttonNames.end,
|
|
2941
|
-
];
|
|
2942
|
-
|
|
2943
|
-
/*
|
|
2944
|
-
Since this could possibly be used in a
|
|
2945
|
-
context without the player and vice versa -
|
|
2946
|
-
will try and make it as self-contained
|
|
2947
|
-
as possible, currently utilizing
|
|
2948
|
-
shadow DOM (style encapsulation as main reason),
|
|
2949
|
-
https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM
|
|
2950
|
-
BEWARE - IE < Edge is unsupported
|
|
2951
|
-
*/
|
|
2952
|
-
|
|
2953
|
-
const CSS = `
|
|
2954
|
-
.vdt-external-controls{
|
|
2955
|
-
display: flex;
|
|
2956
|
-
justify-content: center;
|
|
2957
|
-
align-items: center;
|
|
2958
|
-
}
|
|
2959
|
-
|
|
2960
|
-
.control{
|
|
2961
|
-
flex: 1;
|
|
2962
|
-
flex-grow: 1;
|
|
2963
|
-
height: 100%;
|
|
2964
|
-
align-contents: center;
|
|
2965
|
-
align-self: center;
|
|
2966
|
-
text-align: center;
|
|
2967
|
-
vertical-align: middle;
|
|
2968
|
-
cursor: pointer;
|
|
2969
|
-
user-select: none;
|
|
2970
|
-
height: 20px;
|
|
2971
|
-
padding-top: 10px;
|
|
2972
|
-
padding-bottom: 10px;
|
|
2973
|
-
}
|
|
2974
|
-
|
|
2975
|
-
.control .icon{
|
|
2976
|
-
display: inline-block;
|
|
2977
|
-
height: 20px;
|
|
2978
|
-
white-space: nowrap;
|
|
2979
|
-
opacity: .9;
|
|
2980
|
-
}
|
|
2981
|
-
|
|
2982
|
-
.control:hover .icon{ opacity: 1; }
|
|
2983
|
-
|
|
2984
|
-
.control .icon:before{
|
|
2985
|
-
opacity: 1;
|
|
2986
|
-
flex: 1;
|
|
2987
|
-
align-self: center;
|
|
2988
|
-
content: " ";
|
|
2989
|
-
display: inline-block;
|
|
2990
|
-
margin: 0 auto;
|
|
2991
|
-
|
|
2992
|
-
/* triangles */
|
|
2993
|
-
width: 0;
|
|
2994
|
-
height: 0;
|
|
2995
|
-
border-style: solid;
|
|
2996
|
-
border-width: 16px 0 16px 23px;
|
|
2997
|
-
border-color: transparent transparent transparent ${colors.gray};
|
|
2998
|
-
}
|
|
2999
|
-
|
|
3000
|
-
.vdt-external-controls.${classNames.onDark} .control .icon:before{
|
|
3001
|
-
border-color: transparent transparent transparent ${colors.light};
|
|
3002
|
-
}
|
|
3003
|
-
|
|
3004
|
-
/* specific buttons */
|
|
3005
|
-
|
|
3006
|
-
.control.${buttonNames.start},
|
|
3007
|
-
.control.${buttonNames.end}{
|
|
3008
|
-
height: 20px;
|
|
3009
|
-
}
|
|
3010
|
-
|
|
3011
|
-
.control.${buttonNames.play}{
|
|
3012
|
-
height: 30px;
|
|
3013
|
-
padding-top: 0px;
|
|
3014
|
-
padding-bottom: 0px;
|
|
3015
|
-
}
|
|
3016
|
-
|
|
3017
|
-
.control.${buttonNames.play} .icon{
|
|
3018
|
-
height: 30px;
|
|
3019
|
-
}
|
|
3020
|
-
|
|
3021
|
-
.control.${buttonNames.ff} .icon:before,
|
|
3022
|
-
.control.${buttonNames.fb} .icon:before,
|
|
3023
|
-
.control.${buttonNames.end} .icon:before,
|
|
3024
|
-
.control.${buttonNames.start} .icon:before{
|
|
3025
|
-
border-width: 10px 0 10px 16px;
|
|
3026
|
-
}
|
|
3027
|
-
|
|
3028
|
-
.control.${buttonNames.fb} .icon,
|
|
3029
|
-
.control.${buttonNames.start}{
|
|
3030
|
-
transform: rotate(180deg);
|
|
3031
|
-
}
|
|
3032
|
-
|
|
3033
|
-
.control.${buttonNames.end} .icon:after,
|
|
3034
|
-
.control.${buttonNames.start} .icon:after{
|
|
3035
|
-
content: " ";
|
|
3036
|
-
width: 4px;
|
|
3037
|
-
height: 20px;
|
|
3038
|
-
display: inline-block;
|
|
3039
|
-
background: ${colors.gray};
|
|
3040
|
-
}
|
|
3041
|
-
|
|
3042
|
-
.vdt-external-controls.${classNames.onDark} .control.${buttonNames.end} .icon:after,
|
|
3043
|
-
.vdt-external-controls.${classNames.onDark} .control.${buttonNames.start} .icon:after{
|
|
3044
|
-
background: ${colors.light};
|
|
3045
|
-
}
|
|
3046
|
-
|
|
3047
|
-
/* stateful styles */
|
|
3048
|
-
.control.${buttonNames.play}.playing .icon:before{
|
|
3049
|
-
height: 30px;
|
|
3050
|
-
width: 6px;
|
|
3051
|
-
border-width: 0px 8px 0px 8px;
|
|
3052
|
-
border-color: transparent ${colors.gray} transparent ${colors.gray};
|
|
3053
|
-
}
|
|
3054
|
-
|
|
3055
|
-
.vdt-external-controls.${classNames.onDark} .control.${buttonNames.play}.playing .icon:before{
|
|
3056
|
-
border-color: transparent ${colors.light} transparent ${colors.light};
|
|
3057
|
-
}
|
|
3058
|
-
|
|
3059
|
-
.vdt-external-controls.${classNames.loading} .control.${buttonNames.play}{
|
|
3060
|
-
border-color: transparent #f00 transparent #f00;
|
|
3061
|
-
}
|
|
3062
|
-
`;
|
|
3063
|
-
|
|
3064
|
-
class ExternalControls {
|
|
3065
|
-
constructor(props) {
|
|
3066
|
-
this.props = props;
|
|
3067
|
-
reactiveSetters.apply(this);
|
|
3068
|
-
|
|
3069
|
-
this.state = {
|
|
3070
|
-
playing: false,
|
|
3071
|
-
onDark: false,
|
|
3072
|
-
loading: false,
|
|
3073
|
-
};
|
|
3074
|
-
|
|
3075
|
-
this.shadowRoot = document.createElement('div'); // will attach shadow here, after appending to target
|
|
3076
|
-
this.shadowRoot.className = 'vdt-external-controls-wrapper';
|
|
3077
|
-
this.container = document.createElement('div');
|
|
3078
|
-
this.container.className = 'vdt-external-controls';
|
|
3079
|
-
|
|
3080
|
-
if (this.props.target) {
|
|
3081
|
-
this.props.target.appendChild(this.shadowRoot);
|
|
3082
|
-
this.shadow = this.shadowRoot.attachShadow({ mode: 'open' });
|
|
3083
|
-
// attach styles
|
|
3084
|
-
this.style = document.createElement('style');
|
|
3085
|
-
this.style.type = 'text/css';
|
|
3086
|
-
this.style.appendChild(document.createTextNode(CSS));
|
|
3087
|
-
this.shadow.appendChild(this.style);
|
|
3088
|
-
|
|
3089
|
-
// attach container to shadow root
|
|
3090
|
-
this.shadow.appendChild(this.container);
|
|
3091
|
-
}
|
|
3092
|
-
|
|
3093
|
-
this.handleNewProps(props);
|
|
3094
|
-
this.bindEvents();
|
|
3095
|
-
this.draw();
|
|
3096
|
-
}
|
|
3097
|
-
|
|
3098
|
-
draw() {
|
|
3099
|
-
this.buttons = {}; // map of html nodes for DOM manipulations
|
|
3100
|
-
const excludes = this.props.excludes || [];
|
|
3101
|
-
|
|
3102
|
-
buttons.forEach((buttonName) => {
|
|
3103
|
-
if (excludes.indexOf(buttonName) < 0) {
|
|
3104
|
-
const btn = document.createElement('div');
|
|
3105
|
-
btn.className = `control ${buttonName}`;
|
|
3106
|
-
btn.innerHTML = '<span class="icon"></span>';
|
|
3107
|
-
|
|
3108
|
-
btn.onclick = () => {
|
|
3109
|
-
this.handlePress(buttonName);
|
|
3110
|
-
};
|
|
3111
|
-
|
|
3112
|
-
this.buttons[buttonName] = btn;
|
|
3113
|
-
this.container.appendChild(btn);
|
|
3114
|
-
}
|
|
3115
|
-
});
|
|
3116
|
-
}
|
|
3117
|
-
|
|
3118
|
-
/*
|
|
3119
|
-
bind to play / pause / stop and other events,
|
|
3120
|
-
so that controls reflect the player state
|
|
3121
|
-
*/
|
|
3122
|
-
bindEvents() {
|
|
3123
|
-
if (this.props.player && this.props.player.videojs) {
|
|
3124
|
-
const { player } = this.props;
|
|
3125
|
-
|
|
3126
|
-
player.videojs.on('play', () => {
|
|
3127
|
-
this.playing = true;
|
|
3128
|
-
});
|
|
3129
|
-
|
|
3130
|
-
player.videojs.on('pause', () => {
|
|
3131
|
-
this.playing = false;
|
|
3132
|
-
});
|
|
3133
|
-
|
|
3134
|
-
player.videojs.on('stop', () => {
|
|
3135
|
-
this.playing = false;
|
|
3136
|
-
});
|
|
3137
|
-
}
|
|
3138
|
-
}
|
|
3139
|
-
|
|
3140
|
-
handlePress(buttonName) {
|
|
3141
|
-
if (this.props.player) { // control a vdt player instance directly
|
|
3142
|
-
const player = this.props.player;
|
|
3143
|
-
console.log(player);
|
|
3144
|
-
player.osd && player.osd.disable(); // temporarily disable OSD
|
|
3145
|
-
|
|
3146
|
-
switch (buttonName) {
|
|
3147
|
-
case buttonNames.start:
|
|
3148
|
-
player.toStart();
|
|
3149
|
-
break;
|
|
3150
|
-
case buttonNames.fb:
|
|
3151
|
-
player.triggerHotkey('left');
|
|
3152
|
-
break;
|
|
3153
|
-
case buttonNames.play:
|
|
3154
|
-
player.triggerHotkey('k'); // TODO - triggering hotkeys has a side effect - OSD will give feedback
|
|
3155
|
-
break;
|
|
3156
|
-
case buttonNames.ff:
|
|
3157
|
-
player.triggerHotkey('right');
|
|
3158
|
-
break;
|
|
3159
|
-
case buttonNames.end:
|
|
3160
|
-
player.toEnd();
|
|
3161
|
-
break;
|
|
3162
|
-
}
|
|
3163
|
-
|
|
3164
|
-
player.osd && player.osd.enable(); // re-enable OSD
|
|
3165
|
-
} else {
|
|
3166
|
-
switch (buttonName) {
|
|
3167
|
-
case buttonNames.start:
|
|
3168
|
-
this.props.onPrev && this.props.onPrev();
|
|
3169
|
-
break;
|
|
3170
|
-
case buttonNames.fb:
|
|
3171
|
-
this.props.onFB && this.props.onFB();
|
|
3172
|
-
break;
|
|
3173
|
-
case buttonNames.play:
|
|
3174
|
-
if (this.playing) {
|
|
3175
|
-
this.props.onPause && this.props.onPause();
|
|
3176
|
-
} else {
|
|
3177
|
-
this.props.onPlay && this.props.onPlay();
|
|
3178
|
-
}
|
|
3179
|
-
break;
|
|
3180
|
-
case buttonNames.ff:
|
|
3181
|
-
this.props.onFF && this.props.onFF();
|
|
3182
|
-
break;
|
|
3183
|
-
case buttonNames.end:
|
|
3184
|
-
this.props.onNext && this.props.onNext();
|
|
3185
|
-
break;
|
|
3186
|
-
}
|
|
3187
|
-
}
|
|
3188
|
-
}
|
|
3189
|
-
|
|
3190
|
-
// setters and getters for state
|
|
3191
|
-
set playing(bool) {
|
|
3192
|
-
if (bool) {
|
|
3193
|
-
this.state.playing = true;
|
|
3194
|
-
this.buttons[buttonNames.play].classList.add('playing');
|
|
3195
|
-
} else {
|
|
3196
|
-
this.state.playing = false;
|
|
3197
|
-
this.buttons[buttonNames.play].classList.remove('playing');
|
|
3198
|
-
}
|
|
3199
|
-
}
|
|
3200
|
-
|
|
3201
|
-
get playing() {
|
|
3202
|
-
return this.state.playing;
|
|
3203
|
-
}
|
|
3204
|
-
|
|
3205
|
-
set onDark(bool) {
|
|
3206
|
-
if (bool) {
|
|
3207
|
-
this.state.onDark = true;
|
|
3208
|
-
this.container.classList.add(classNames.onDark);
|
|
3209
|
-
} else {
|
|
3210
|
-
this.state.onDark = false;
|
|
3211
|
-
this.container.classList.remove(classNames.onDark);
|
|
3212
|
-
}
|
|
3213
|
-
}
|
|
3214
|
-
|
|
3215
|
-
get onDark() {
|
|
3216
|
-
return this.container.classList.contains(classNames.onDark);
|
|
3217
|
-
}
|
|
3218
|
-
|
|
3219
|
-
set loading(bool) {
|
|
3220
|
-
if (bool) {
|
|
3221
|
-
this.state.loading = true;
|
|
3222
|
-
this.container.classList.add(classNames.loading);
|
|
3223
|
-
} else {
|
|
3224
|
-
this.state.loading = false;
|
|
3225
|
-
this.container.classList.remove(classNames.loading);
|
|
3226
|
-
}
|
|
3227
|
-
}
|
|
3228
|
-
|
|
3229
|
-
get loading() {
|
|
3230
|
-
return this.state.loading;
|
|
3231
|
-
}
|
|
3232
|
-
}
|
|
3233
|
-
|
|
3234
|
-
ExternalControls.buttonNames = buttonNames;
|
|
3235
|
-
|
|
3236
2107
|
exports.ExternalControls = ExternalControls;
|
|
3237
2108
|
exports.Player = Player;
|
|
3238
2109
|
exports.SeekBar = SeekBar;
|