@vidispine/vdt-videojs 23.2.0-pre.1 → 23.2.0

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/src/menu.js DELETED
@@ -1,373 +0,0 @@
1
- /* eslint-disable no-param-reassign */
2
- /* eslint-disable no-multi-assign */
3
- /* eslint-disable no-unused-expressions */
4
- /* eslint-disable max-classes-per-file */
5
- import mousetrap from 'mousetrap';
6
-
7
- const constants = Object.freeze({
8
- className: 'vdt-menu',
9
- menuClassName: 'menu',
10
- subLvlClassName: 'sub-level',
11
- menuItemClassName: 'menu-item',
12
- animationLength: 300,
13
- defaults: {
14
- bgColor: 'rgba(0,0,0,.8)',
15
- textColor: '#999',
16
- textColorDark: '#333',
17
- textColorLight: 'rgba(255,255,255)',
18
- bgColorLight: 'rgba(255,255,255,.2)',
19
- bgColorSelected: 'rgba(255,255,255,.1)',
20
- },
21
- });
22
-
23
- const CSS = () => `
24
- .${constants.menuClassName}{
25
- position: relative;
26
- height: 100%;
27
- width: 200%;
28
- // min-width: 200px;
29
- right: 0px;
30
- bottom: 0px;
31
- background: ${constants.defaults.bgColor};
32
- z-index: 1px;
33
- transform: translate3d(100%, 0px, 0px);
34
- transition: all 300ms ease-in-out;
35
- box-shadow: 0px 0px 30px rgb;
36
- -webkit-backdrop-filter: blur(10px);
37
- overflow: hidden;
38
- }
39
-
40
- .${constants.menuClassName} .level-1{
41
- float: left;
42
- }
43
-
44
- .${constants.menuClassName} div h3{
45
- padding: 16px 24px;
46
- font-size: 12px;
47
- border-bottom: 1px solid ${constants.defaults.bgColorLight}
48
- }
49
-
50
- .${constants.menuClassName} .level-2 h3{
51
- cursor: pointer;
52
- position: relative;
53
- }
54
- .${constants.menuClassName} .level-2 h3:before{
55
- content: '◂';
56
- margin-left: -12px;
57
- width: 12px;
58
- display: inline-block;
59
- position: absolute;
60
- margin-top: -1px;
61
- }
62
-
63
- .${constants.menuClassName} .level-1,
64
- .${constants.menuClassName} .level-2{
65
- transform: translate3d(0px, 0px, 0px);
66
- transition: all 300ms ease-in-out;
67
- width: 50%;
68
- height: 100%;
69
- float: left;
70
- }
71
-
72
- .${constants.menuClassName}.sub-level .level-1,
73
- .${constants.menuClassName}.sub-level .level-2{
74
- transform: translate3d(-100%, 0px, 0px);
75
- }
76
-
77
- .${constants.menuClassName} table{
78
- border-collapse: collapse;
79
- width: 100%;
80
- }
81
-
82
- .${constants.menuClassName}.open{
83
- transform: translate3d(0px, 0px, 0px);
84
- }
85
-
86
- .${constants.menuClassName} tr{
87
- cursor: pointer;
88
- height: 40px;
89
- }
90
-
91
- .${constants.menuClassName} tr.selected{
92
- background: ${constants.defaults.bgColorSelected};
93
- }
94
-
95
-
96
- .${constants.menuClassName} tr td{
97
- color: white;
98
- font-size: 15px;
99
- vertical-align: middle;
100
- }
101
-
102
-
103
- .${constants.menuClassName} tr:hover td{
104
- color: white;
105
- background: ${constants.defaults.bgColorLight};
106
- }
107
-
108
- .${constants.menuClassName} tr td.title{
109
- padding-top: 12px;
110
- padding-bottom: 12px;
111
- font-weight: 300;
112
- font-family: Helvetica, Arial, sans-serif;
113
- }
114
-
115
- .${constants.menuClassName} tr td.caret{
116
- font-size: 12px;
117
- }
118
-
119
- .${constants.menuClassName} tr td:first-child{
120
- padding-left: 24px;
121
- }
122
-
123
- .${constants.menuClassName} tr td:last-child{
124
- padding-right: 16px;
125
- }
126
-
127
- .${constants.menuClassName} tr.has-items td:last-child{
128
- text-align: right;
129
- }
130
-
131
- .${constants.menuClassName} tr.has-items td.subtitle{
132
- font-size: 12px;
133
- text-align: right;
134
- color: ${constants.defaults.textColorLight};
135
- }
136
- `;
137
-
138
- class MenuDisplayItem {
139
- constructor(props) {
140
- this.props = props;
141
-
142
- const classNames = [
143
- constants.menuItemClassName,
144
- this.props.items && 'has-items',
145
- this.props.selected && 'selected',
146
- ];
147
- this.container = document.createElement('tr');
148
- this.container.className = classNames.join(' ');
149
-
150
- if (this.props.target) this.props.target.appendChild(this.container);
151
-
152
- // bind click
153
- this.container.onclick = (event) => {
154
- if (this.props.onClick) this.props.onClick(event);
155
- };
156
-
157
- this.render();
158
- }
159
-
160
- render() {
161
- if (this.props.items) {
162
- // will transition to 2nd level
163
- this.container.innerHTML = `
164
- <td class="title"></td>
165
- <td class="subtitle"></td>
166
- <td class="caret">▷</td>
167
- `;
168
- } else {
169
- this.container.innerHTML = `
170
- <td class="title"></td>
171
- `;
172
- }
173
-
174
- const titleNode = this.container.getElementsByClassName('title')[0];
175
- const subtitleNode = this.props.items
176
- ? this.container.getElementsByClassName('subtitle')[0]
177
- : false;
178
-
179
- titleNode.textContent = this.props.title;
180
- if (subtitleNode) subtitleNode.textContent = this.props.subtitle;
181
- }
182
- }
183
-
184
- export default class Menu {
185
- constructor(props) {
186
- this.props = props;
187
-
188
- this.container = document.createElement('div');
189
- this.container.className = `${constants.className}`;
190
-
191
- this.state = {
192
- opened: false,
193
- selectedItem: 0,
194
- items: [],
195
- subItems: [],
196
- };
197
-
198
- this.mount();
199
- this.draw();
200
- }
201
-
202
- mount() {
203
- // this.props.target && this.props.target.appendChild(this.container)
204
- if (this.props.target) {
205
- // container node, acts as an overlay in is stylable from outside
206
- this.container.style.position = 'absolute';
207
- this.container.style.bottom = this.container.style.right = '0px';
208
- this.container.style.height = '100%';
209
- this.container.style.overflow = 'hidden';
210
- this.container.style.width = '30%';
211
- this.container.style.minWidth = '250px';
212
- this.container.style.maxWidth = '320px';
213
-
214
- // shadow node encapsulates style and prevents css collisions
215
- this.shadow = this.container.attachShadow({ mode: 'open' });
216
- if (this.props.target) this.props.target.appendChild(this.container);
217
-
218
- // node for menu itself
219
- this.menuContainer = document.createElement('div');
220
- this.menuContainer.className = 'menu';
221
-
222
- this.shadow.appendChild(this.menuContainer);
223
-
224
- // attach styles
225
- this.style = document.createElement('style');
226
- this.style.type = 'text/css';
227
- this.style.innerHTML = CSS();
228
- this.shadow.appendChild(this.style);
229
- }
230
- }
231
-
232
- draw() {
233
- // first draw
234
- const mainDiv = document.createElement('div');
235
- mainDiv.className = 'level-1';
236
- this.mainLevel = document.createElement('table');
237
- mainDiv.innerHTML = '<h3>Settings</h3>';
238
- mainDiv.appendChild(this.mainLevel);
239
-
240
- const subDiv = document.createElement('div');
241
- subDiv.className = 'level-2';
242
- this.subLvlTitle = document.createElement('h3');
243
- this.subLvlTitle.onclick = () => {
244
- this.up();
245
- };
246
- subDiv.appendChild(this.subLvlTitle);
247
- this.secondaryLevel = document.createElement('table');
248
- subDiv.appendChild(this.secondaryLevel);
249
-
250
- this.menuContainer.appendChild(mainDiv);
251
- this.menuContainer.appendChild(subDiv);
252
-
253
- this.props.items.forEach((menuItem) => {
254
- // get selected item title if such exists
255
- const activeTitle = menuItem.items[menuItem.getActiveIndex(menuItem.items)].title || '';
256
- const displayItem = new MenuDisplayItem({
257
- target: this.mainLevel,
258
- subtitle: activeTitle,
259
- onClick: () => {
260
- this.handleSupItemSelected(menuItem);
261
- },
262
- ...menuItem,
263
- });
264
-
265
- this.state.items.push(displayItem);
266
- });
267
- }
268
-
269
- open() {
270
- this.render();
271
-
272
- this.menuContainer.classList.add('open');
273
- if (this.props.onOpen) this.props.onOpen();
274
- this.state.opened = true;
275
-
276
- // close the menu when user clicks outside it
277
- if (!this.handleClicksWhenMenuOpened) {
278
- // eslint-disable-next-line func-names
279
- this.handleClicksWhenMenuOpened = function (event) {
280
- if (this.state.opened) {
281
- event.stopPropagation();
282
- const isClickInside = this.container.contains(event.target);
283
- if (!isClickInside) {
284
- this.close();
285
- }
286
- }
287
- }.bind(this);
288
- }
289
-
290
- this.handleClicksWhenMenuOpenedTimeout = setTimeout(() => {
291
- document.addEventListener('click', this.handleClicksWhenMenuOpened);
292
- mousetrap.bind('esc', this.close.bind(this)); // esc closes menu aswell
293
- }, constants.animationLength);
294
- }
295
-
296
- close() {
297
- this.menuContainer.classList.remove('open');
298
- this.state.opened = false;
299
-
300
- if (this.handleClicksWhenMenuOpenedTimeout)
301
- clearTimeout(this.handleClicksWhenMenuOpenedTimeout);
302
- document.removeEventListener('click', this.handleClicksWhenMenuOpened);
303
-
304
- if (this.props.onClose) this.props.onClose();
305
-
306
- mousetrap.unbind('esc');
307
- }
308
-
309
- toggle() {
310
- if (this.state.opened) {
311
- this.close();
312
- } else {
313
- this.open();
314
- }
315
- }
316
-
317
- up() {
318
- // go to level 1
319
- this.menuContainer.classList.remove(constants.subLvlClassName);
320
- this.render();
321
- }
322
-
323
- handleSupItemSelected(item) {
324
- this.subLvlTitle.textContent = item.title;
325
- this.renderSubItems(item.items, item.getActiveIndex(item.items));
326
- this.menuContainer.classList.add(constants.subLvlClassName);
327
- }
328
-
329
- renderSubItems(items, activeIndex = false) {
330
- this.secondaryLevel.innerHTML = '';
331
-
332
- const subItemRefs = [];
333
- items.forEach((menuItem, index) => {
334
- const displayItem = new MenuDisplayItem({
335
- target: this.secondaryLevel,
336
- ...menuItem,
337
- onClick: (event) => {
338
- this.handleSubItemSelected(event, menuItem);
339
- },
340
- selected: index === activeIndex, // mark selected
341
- });
342
-
343
- subItemRefs.push(displayItem);
344
- });
345
-
346
- this.state.subItems = subItemRefs;
347
- }
348
-
349
- handleSubItemSelected(event, item) {
350
- this.close();
351
- if (item.onClick) item.onClick(event, item);
352
- this.up();
353
- }
354
-
355
- get opened() {
356
- return this.state.opened;
357
- }
358
-
359
- set opened(bool) {
360
- this.state.opened = bool;
361
- }
362
-
363
- render() {
364
- // update selections at level 1
365
- this.state.items.forEach((menuDisplayItem, index) => {
366
- const { items } = this.props;
367
- const activeIndex = items[index].getActiveIndex(items[index].items);
368
- const activeTitle = items[index].items[activeIndex].title;
369
- menuDisplayItem.props.subtitle = activeTitle;
370
- menuDisplayItem.render();
371
- });
372
- }
373
- }
@@ -1,78 +0,0 @@
1
- import { Meta } from '@storybook/addon-docs';
2
-
3
- import { docsParameters } from '@vidispine/vdt-storybook';
4
-
5
- <Meta title="vdt-videojs/Player Menu/Example Usage" parameters={docsParameters} />
6
-
7
- ## Example Usage
8
-
9
- It's possible to pass your own menu items to a new Player instance during initialization like so:
10
-
11
- ```js
12
- import { Player } from '@vidispine/vdt-videojs';
13
-
14
- const target = {
15
- /* ... */
16
- };
17
- const testData = {
18
- /* ... */
19
- };
20
- const menuItems = {
21
- /* ... */
22
- };
23
- const randIndex = 0; // random index
24
-
25
- const player = new Player({
26
- target,
27
- sources: testData[randIndex].sources,
28
- menuItems,
29
- // ...
30
- });
31
- ```
32
-
33
- The items can be defined as follows:
34
-
35
- ```js
36
- import { Player } from '@vidispine/vdt-videojs';
37
-
38
- const player = new Player({
39
- /* ... */
40
- });
41
- const menuItems = [
42
- {
43
- title: 'Example 1',
44
- // predicate method for determining active index
45
- getActiveIndex: (subitems) => {
46
- let activeIndex = 0;
47
-
48
- subitems.forEach((item, index) => {
49
- if (item.src === player.src) {
50
- activeIndex = index;
51
- }
52
- });
53
-
54
- return activeIndex;
55
- },
56
- items: [
57
- {
58
- title: 'Option 1',
59
- src: '//vjs.zencdn.net/v/oceans.mp4',
60
- onClick: (event, item) => {
61
- console.log(event, item, player);
62
- },
63
- },
64
- {
65
- title: 'Option 2',
66
- src: '//commondatastorage.googleapis.com/gtv-videos-bucket/sample/TearsOfSteel.mp4',
67
- someKey: 'value', // store arbitrary data
68
- onClick: (event, item) => {
69
- console.log(event, item, player);
70
- },
71
- },
72
- ],
73
- },
74
- ];
75
- ```
76
-
77
- Note the `getActiveIndex` method on top level items - this method is invoked
78
- during opening of the menu, while navigating up to main level and on the first draw to determine the active (selected) item.
package/src/osd.js DELETED
@@ -1,105 +0,0 @@
1
- import { osd } from './constants';
2
-
3
- export default class OSD {
4
- constructor(props) {
5
- this.props = props;
6
-
7
- this.state = {
8
- enabled: true,
9
- };
10
-
11
- this.container = document.createElement('div');
12
- this.container.className = 'vdt-player-osd';
13
-
14
- // vertically center with css
15
- this.container.innerHTML = `
16
- <table>
17
- <tbody>
18
- <td>
19
- <div class="osd-feedback-icon"></div>
20
- </td>
21
- </tbody>
22
- </table>
23
- `;
24
-
25
- // eslint-disable-next-line prefer-destructuring
26
- this.iconEl = this.container.getElementsByClassName('osd-feedback-icon')[0];
27
-
28
- if (this.props.target) this.props.target.appendChild(this.container);
29
- }
30
-
31
- feedback(feedbackType, details = null) {
32
- // details - {} - can contain additional data
33
- if (!this.state.enabled) {
34
- return;
35
- }
36
-
37
- let className;
38
-
39
- switch (feedbackType) {
40
- case osd.pause:
41
- className = 'pause';
42
- break;
43
- case osd.play:
44
- className = 'play';
45
- break;
46
- case osd.volchange:
47
- // eslint-disable-next-line no-case-declarations
48
- const currentVolumeLevel = details.volume;
49
- // eslint-disable-next-line no-case-declarations
50
- let perceivedVolumeLevel; // 'low' | 'mid' | 'high' string to utilize video js eisting icons
51
-
52
- /*
53
- case switch will be too slow for this, if's are 2x more performant for this case
54
- (Except in IE)
55
- so... no case switch inside case switch this time :/
56
- */
57
-
58
- // values here are a bit of a guess, but they seem to match videojs thresholds
59
- if (currentVolumeLevel === 0) {
60
- perceivedVolumeLevel = 'null';
61
- } else if (currentVolumeLevel > 0.65) {
62
- perceivedVolumeLevel = 'high';
63
- } else if (currentVolumeLevel < 0.35) {
64
- perceivedVolumeLevel = 'low';
65
- } else {
66
- perceivedVolumeLevel = 'mid';
67
- }
68
-
69
- className = `volchange ${perceivedVolumeLevel}`;
70
- break;
71
- case osd.jumpForward:
72
- className = 'forward-jump';
73
- break;
74
- case osd.jumpBackward:
75
- className = 'backward-jump';
76
- break;
77
- default:
78
- // do nothing
79
- break;
80
- }
81
-
82
- if (this.osdTimeout) {
83
- // should clear previous timeout/classname if in progress
84
- this.container.classList.remove('active');
85
- clearTimeout(this.osdTimeout);
86
- }
87
-
88
- // do feedback
89
- this.container.classList.add('active');
90
- this.osdTimeout = setTimeout(() => {
91
- this.container.classList.remove('active');
92
- }, 200);
93
-
94
- // get specific with classnames
95
- this.iconEl.className = `osd-feedback-icon ${className}`; // gets an overwrite each time
96
- }
97
-
98
- disable() {
99
- this.state.enabled = false;
100
- }
101
-
102
- enable() {
103
- this.state.enabled = true;
104
- }
105
- }
@@ -1,114 +0,0 @@
1
- import { Meta } from '@storybook/addon-docs';
2
-
3
- import { docsParameters } from '@vidispine/vdt-storybook';
4
-
5
- <Meta title="vdt-videojs/Player/Class Methods" parameters={docsParameters} />
6
-
7
- ## Class Methods
8
-
9
- <table>
10
- <thead>
11
- <tr>
12
- <th>Method</th>
13
- <th>Description</th>
14
- <th>Associated hotkey</th>
15
- </tr>
16
- </thead>
17
- <tbody>
18
- <tr>
19
- <td>.togglePlayback()</td>
20
- <td>toggle Play / Pause</td>
21
- <td>Space, K</td>
22
- </tr>
23
- <tr>
24
- <td>.pause()</td>
25
- <td>Pause</td>
26
- <td />
27
- </tr>
28
- <tr>
29
- <td>.play()</td>
30
- <td>Play</td>
31
- <td />
32
- </tr>
33
- <tr>
34
- <td>.volumeUp()</td>
35
- <td>Increase playback volume</td>
36
- <td>Arrow up</td>
37
- </tr>
38
- <tr>
39
- <td>.volumeDown()</td>
40
- <td>Decrease playback volume</td>
41
- <td>Arrow down</td>
42
- </tr>
43
- <tr>
44
- <td>.toggleMute()</td>
45
- <td>Mute / Unmute audio</td>
46
- <td>M</td>
47
- </tr>
48
- <tr>
49
- <td>.toggleFullscreen()</td>
50
- <td>Toggle fullscreen</td>
51
- <td>F</td>
52
- </tr>
53
- <tr>
54
- <td>.jumpForward()</td>
55
- <td>Jump 10 seconds forward</td>
56
- <td>L</td>
57
- </tr>
58
- <tr>
59
- <td>.jumpBackward()</td>
60
- <td>Jump 10 seconds backward</td>
61
- <td>J</td>
62
- </tr>
63
- <tr>
64
- <td>.frameForward()</td>
65
- <td>Navigate to next frame</td>
66
- <td>Arrow right</td>
67
- </tr>
68
- <tr>
69
- <td>.frameBackward()</td>
70
- <td>Navigate to previous frame</td>
71
- <td>Arrow left</td>
72
- </tr>
73
- <tr>
74
- <td>.toggleSubs()</td>
75
- <td>Toggle subtitles on / off if any</td>
76
- <td>C</td>
77
- </tr>
78
- <tr>
79
- <td>.disableSubs()</td>
80
- <td>Turn subtitles off</td>
81
- <td />
82
- </tr>
83
- <tr>
84
- <td>.enableSubs()</td>
85
- <td>Turn subtitles on</td>
86
- <td />
87
- </tr>
88
- <tr>
89
- <td>.volume</td>
90
- <td>Returns current volume level (0-1)</td>
91
- <td />
92
- </tr>
93
- <tr>
94
- <td>.volume = 0.345</td>
95
- <td>Sets volume level (0-1)</td>
96
- <td />
97
- </tr>
98
- <tr>
99
- <td>.toStart()</td>
100
- <td>Navigate to start of the video</td>
101
- <td />
102
- </tr>
103
- <tr>
104
- <td>.toEnd()</td>
105
- <td>Navigate to end of the video</td>
106
- <td />
107
- </tr>
108
- <tr>
109
- <td>.destroy()</td>
110
- <td>Deconstructor</td>
111
- <td />
112
- </tr>
113
- </tbody>
114
- </table>