@vidispine/vdt-videojs 21.3.0 → 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} +755 -55
- package/dist/index.es.js +2099 -0
- package/dist/index.js +2112 -0
- package/dist/index.umd.js +2115 -0
- 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 -3240
- package/lib/index.esm.js +0 -3227
- package/lib/index.umd.js +0 -3243
- 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
package/src/seekBar.js
CHANGED
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
/* eslint-disable max-classes-per-file */
|
|
6
6
|
|
|
7
7
|
import mousetrap from 'mousetrap';
|
|
8
|
-
|
|
8
|
+
|
|
9
9
|
import { classNames, colors } from './constants';
|
|
10
|
+
import { truncate, sanitize, reactiveSetters } from './helpers';
|
|
10
11
|
|
|
11
12
|
const constants = Object.freeze({
|
|
12
13
|
className: 'vdt-seekbar',
|
|
@@ -249,7 +250,7 @@ export default class SeekBar {
|
|
|
249
250
|
this.state = {
|
|
250
251
|
in: null, // in seconds from 0
|
|
251
252
|
out: null,
|
|
252
|
-
markersEnabled:
|
|
253
|
+
markersEnabled: this.props.markersEnabled === undefined ? true : this.props.markersEnabled,
|
|
253
254
|
regions: [], // array with regions providing {in: 0, out: 12} and possibly more
|
|
254
255
|
dragging: false,
|
|
255
256
|
};
|
|
@@ -264,8 +265,8 @@ export default class SeekBar {
|
|
|
264
265
|
this.style.type = 'text/css';
|
|
265
266
|
|
|
266
267
|
// colors from props
|
|
267
|
-
const bgColor =
|
|
268
|
-
const fillColor =
|
|
268
|
+
const bgColor = this.props.bgColor ? this.props.bgColor : constants.defaults.bgColor;
|
|
269
|
+
const fillColor = this.props.fillColor ? this.props.fillColor : constants.defaults.fillColor;
|
|
269
270
|
|
|
270
271
|
this.style.innerHTML = CSS(sanitize(bgColor), sanitize(fillColor));
|
|
271
272
|
this.shadow.appendChild(this.style);
|
|
@@ -294,7 +295,8 @@ export default class SeekBar {
|
|
|
294
295
|
then could use requestAnimationFrame and
|
|
295
296
|
get a smoother animation at more expense
|
|
296
297
|
*/
|
|
297
|
-
bindEvents() {
|
|
298
|
+
bindEvents() {
|
|
299
|
+
// bind to vdt player instance
|
|
298
300
|
if (this.props.player) {
|
|
299
301
|
const { player } = this.props;
|
|
300
302
|
player.videojs.on('timeupdate', () => {
|
|
@@ -370,9 +372,10 @@ export default class SeekBar {
|
|
|
370
372
|
}
|
|
371
373
|
|
|
372
374
|
unbindHotKeys() {
|
|
373
|
-
this.bindings &&
|
|
374
|
-
|
|
375
|
-
|
|
375
|
+
this.bindings &&
|
|
376
|
+
this.bindings.forEach((binding) => {
|
|
377
|
+
mousetrap.unbind(binding.key);
|
|
378
|
+
});
|
|
376
379
|
}
|
|
377
380
|
|
|
378
381
|
handleSeek(event) {
|
|
@@ -389,7 +392,7 @@ export default class SeekBar {
|
|
|
389
392
|
// callback for clicking on a region, if callback returns false, no seek happens
|
|
390
393
|
// TODO - make a convention of returning true / false to break from seek
|
|
391
394
|
if (this.props.onRegionClick) {
|
|
392
|
-
preventSeek =
|
|
395
|
+
preventSeek = this.props.onRegionClick(region);
|
|
393
396
|
if (!preventSeek) {
|
|
394
397
|
player.seekTo(region.in);
|
|
395
398
|
}
|
|
@@ -409,7 +412,8 @@ export default class SeekBar {
|
|
|
409
412
|
if (clickedOnRegion) return;
|
|
410
413
|
}
|
|
411
414
|
|
|
412
|
-
const seekFractionX =
|
|
415
|
+
const seekFractionX =
|
|
416
|
+
(event.clientX - this.bar.getBoundingClientRect().left) / this.bar.offsetWidth;
|
|
413
417
|
// -> 0.34732
|
|
414
418
|
|
|
415
419
|
const timeToSeek = seekFractionX * player.videojs.duration();
|
|
@@ -428,7 +432,8 @@ export default class SeekBar {
|
|
|
428
432
|
left = e.clientX - barOffset;
|
|
429
433
|
const pxDragged = Math.abs(mouseDownEvent.clientX - e.clientX);
|
|
430
434
|
|
|
431
|
-
if (left >= 0 && left < barWidth && pxDragged > 1) {
|
|
435
|
+
if (left >= 0 && left < barWidth && pxDragged > 1) {
|
|
436
|
+
// prevent out-of-bounds
|
|
432
437
|
this.dragging = true;
|
|
433
438
|
const fractionFromStart = parseFloat(left) / barWidth;
|
|
434
439
|
const seconds = fractionFromStart * duration;
|
|
@@ -468,13 +473,18 @@ export default class SeekBar {
|
|
|
468
473
|
|
|
469
474
|
// handle drag
|
|
470
475
|
|
|
471
|
-
this.bar.addEventListener(
|
|
472
|
-
|
|
476
|
+
this.bar.addEventListener(
|
|
477
|
+
'mousedown',
|
|
478
|
+
(e) => {
|
|
479
|
+
e.preventDefault(); // prevents selection cursor
|
|
473
480
|
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
481
|
+
if (!this.dragging) {
|
|
482
|
+
// don't attach listeners if something is already dragging
|
|
483
|
+
this.handleSeekDrag(e);
|
|
484
|
+
}
|
|
485
|
+
},
|
|
486
|
+
false,
|
|
487
|
+
);
|
|
478
488
|
|
|
479
489
|
this.fill = document.createElement('div');
|
|
480
490
|
this.fill.className = 'fill';
|
|
@@ -493,10 +503,11 @@ export default class SeekBar {
|
|
|
493
503
|
this.drawMarkers();
|
|
494
504
|
}
|
|
495
505
|
|
|
496
|
-
drawMarkers() {
|
|
506
|
+
drawMarkers() {
|
|
507
|
+
// TODO - add touch events
|
|
497
508
|
if (this.markersEnabled) {
|
|
498
|
-
const markerIn = this.markers[constants.markerTypes.in] = document.createElement('div');
|
|
499
|
-
const markerOut = this.markers[constants.markerTypes.out] = document.createElement('div');
|
|
509
|
+
const markerIn = (this.markers[constants.markerTypes.in] = document.createElement('div'));
|
|
510
|
+
const markerOut = (this.markers[constants.markerTypes.out] = document.createElement('div'));
|
|
500
511
|
markerIn.className = `marker ${constants.markerTypes.in}`;
|
|
501
512
|
markerOut.className = `marker ${constants.markerTypes.out}`;
|
|
502
513
|
|
|
@@ -504,19 +515,27 @@ export default class SeekBar {
|
|
|
504
515
|
const handleOut = document.createElement('div');
|
|
505
516
|
handleIn.className = handleOut.className = 'handle';
|
|
506
517
|
|
|
507
|
-
handleIn.addEventListener(
|
|
508
|
-
|
|
509
|
-
e
|
|
518
|
+
handleIn.addEventListener(
|
|
519
|
+
'mousedown',
|
|
520
|
+
(e) => {
|
|
521
|
+
e.preventDefault(); // prevents selection cursor
|
|
522
|
+
e.stopPropagation(); // prevent triggering seek bar drag
|
|
510
523
|
|
|
511
|
-
|
|
512
|
-
|
|
524
|
+
this.handleMarkerDrag(markerIn, constants.markerTypes.in, e);
|
|
525
|
+
},
|
|
526
|
+
false,
|
|
527
|
+
);
|
|
513
528
|
|
|
514
|
-
handleOut.addEventListener(
|
|
515
|
-
|
|
516
|
-
e
|
|
529
|
+
handleOut.addEventListener(
|
|
530
|
+
'mousedown',
|
|
531
|
+
(e) => {
|
|
532
|
+
e.preventDefault(); // prevents selection cursor
|
|
533
|
+
e.stopPropagation(); // prevent triggering seek bar drag
|
|
517
534
|
|
|
518
|
-
|
|
519
|
-
|
|
535
|
+
this.handleMarkerDrag(markerOut, constants.markerTypes.out, e);
|
|
536
|
+
},
|
|
537
|
+
false,
|
|
538
|
+
);
|
|
520
539
|
|
|
521
540
|
markerIn.appendChild(handleIn);
|
|
522
541
|
markerOut.appendChild(handleOut);
|
|
@@ -534,7 +553,7 @@ export default class SeekBar {
|
|
|
534
553
|
if (this.state.regions) {
|
|
535
554
|
// check if any region contains in / out matching value
|
|
536
555
|
const matchingRegions = [];
|
|
537
|
-
const isRegional =
|
|
556
|
+
const isRegional = matchingRegions.length > 0;
|
|
538
557
|
if (isRegional) {
|
|
539
558
|
this.markers[marker.type].classList.add('regional');
|
|
540
559
|
} else {
|
|
@@ -545,10 +564,13 @@ export default class SeekBar {
|
|
|
545
564
|
this.drawInAndOutRegion();
|
|
546
565
|
}
|
|
547
566
|
|
|
548
|
-
drawInAndOutRegion() {
|
|
567
|
+
drawInAndOutRegion() {
|
|
568
|
+
// triggered after drawMarkers if in + out is set
|
|
549
569
|
if (this.state.in !== null && this.state.out !== null) {
|
|
550
570
|
this.region.style.left = this.markers[constants.markerTypes.in].style.left;
|
|
551
|
-
this.region.style.right = `${
|
|
571
|
+
this.region.style.right = `${
|
|
572
|
+
100 - parseFloat(this.markers[constants.markerTypes.out].style.left.replace('%', ''))
|
|
573
|
+
}%`;
|
|
552
574
|
} else {
|
|
553
575
|
// remove region div or hide it
|
|
554
576
|
}
|
|
@@ -559,7 +581,8 @@ export default class SeekBar {
|
|
|
559
581
|
but find out if there is a mobile use
|
|
560
582
|
case before that
|
|
561
583
|
*/
|
|
562
|
-
handleMarkerDrag(markerNode, type, mouseDownEvent) {
|
|
584
|
+
handleMarkerDrag(markerNode, type, mouseDownEvent) {
|
|
585
|
+
// marker node, marker type (constants.markerTypes)
|
|
563
586
|
const barOffset = this.bar.getBoundingClientRect().left; // px from page left side
|
|
564
587
|
const barWidth = this.bar.getBoundingClientRect().width; // seek bar width
|
|
565
588
|
const duration = this.props.player.videojs.duration(); // in secondsā
|
|
@@ -567,15 +590,20 @@ export default class SeekBar {
|
|
|
567
590
|
|
|
568
591
|
const drag = (e) => {
|
|
569
592
|
const pxDragged = Math.abs(mouseDownEvent.clientX - e.clientX);
|
|
570
|
-
const markerOffset =
|
|
593
|
+
const markerOffset =
|
|
594
|
+
type === constants.markerTypes.in
|
|
595
|
+
? constants.defaults.markerWidth / 2
|
|
596
|
+
: -(constants.defaults.markerWidth / 2);
|
|
571
597
|
const left = e.clientX - barOffset + markerOffset;
|
|
572
598
|
|
|
573
|
-
if (left >= 0 && left < barWidth && pxDragged > 1) {
|
|
599
|
+
if (left >= 0 && left < barWidth && pxDragged > 1) {
|
|
600
|
+
// prevent out-of-bounds
|
|
574
601
|
dragHappened = this.dragging = true;
|
|
575
602
|
markerNode.style.left = `${left}px`;
|
|
576
603
|
markerNode.classList.add('active');
|
|
577
604
|
|
|
578
|
-
const fractionFromStart =
|
|
605
|
+
const fractionFromStart =
|
|
606
|
+
parseFloat(markerNode.getBoundingClientRect().left - barOffset) / barWidth;
|
|
579
607
|
const seconds = fractionFromStart * duration;
|
|
580
608
|
this.props.player.videojs.currentTime(seconds);
|
|
581
609
|
}
|
|
@@ -590,7 +618,8 @@ export default class SeekBar {
|
|
|
590
618
|
document.removeEventListener('mousemove', drag, false);
|
|
591
619
|
document.removeEventListener('mouseup', stopDrag, false);
|
|
592
620
|
|
|
593
|
-
const fractionFromStart =
|
|
621
|
+
const fractionFromStart =
|
|
622
|
+
parseFloat(markerNode.getBoundingClientRect().left - barOffset) / barWidth;
|
|
594
623
|
const seconds = fractionFromStart * duration;
|
|
595
624
|
this[type] = seconds;
|
|
596
625
|
this.props.player.videojs.currentTime(seconds);
|
|
@@ -633,7 +662,8 @@ export default class SeekBar {
|
|
|
633
662
|
removedMarker = true;
|
|
634
663
|
}
|
|
635
664
|
|
|
636
|
-
if (removedMarker) {
|
|
665
|
+
if (removedMarker) {
|
|
666
|
+
// if a marker was removed, region no longer is valid
|
|
637
667
|
this.region.style.left = 'initial';
|
|
638
668
|
this.region.style.right = 'initial';
|
|
639
669
|
}
|
|
@@ -734,12 +764,16 @@ export default class SeekBar {
|
|
|
734
764
|
}
|
|
735
765
|
}
|
|
736
766
|
|
|
737
|
-
set regions(regionArray) {
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
767
|
+
set regions(regionArray) {
|
|
768
|
+
// different than i / o markers
|
|
769
|
+
if (this.state.regions.length < 1) {
|
|
770
|
+
// first time add
|
|
771
|
+
regionArray &&
|
|
772
|
+
regionArray.forEach((region) => {
|
|
773
|
+
this.addRegion(region);
|
|
774
|
+
});
|
|
775
|
+
} else {
|
|
776
|
+
// state redraw
|
|
743
777
|
this.state.regions.forEach((region, index) => {
|
|
744
778
|
this.removeRegion(index);
|
|
745
779
|
});
|
|
@@ -772,15 +806,18 @@ export default class SeekBar {
|
|
|
772
806
|
if (regionObj.constructor.name === Region.name) {
|
|
773
807
|
this.state.regions.push(regionObj);
|
|
774
808
|
this.drawRegion(regionObj);
|
|
775
|
-
} else {
|
|
809
|
+
} else {
|
|
810
|
+
// try to construct region if has accepted properties
|
|
776
811
|
this.addRegion(new Region(regionObj));
|
|
777
812
|
}
|
|
778
813
|
}
|
|
779
814
|
|
|
780
815
|
removeRegion(param) {
|
|
781
|
-
if (typeof param === typeof Region) {
|
|
816
|
+
if (typeof param === typeof Region) {
|
|
817
|
+
// TODO - implement this - find by region obj
|
|
782
818
|
// find said matching region
|
|
783
|
-
} else {
|
|
819
|
+
} else {
|
|
820
|
+
// it's an index
|
|
784
821
|
this.state.regions[param].el.remove();
|
|
785
822
|
this.state.regions[param] = null;
|
|
786
823
|
delete this.state.regions[param];
|
package/src/timeCodeDisplay.js
CHANGED
|
@@ -3,14 +3,10 @@
|
|
|
3
3
|
/* eslint-disable no-plusplus */
|
|
4
4
|
/* eslint-disable no-unused-expressions */
|
|
5
5
|
|
|
6
|
-
const timeCodeNodeNames = [
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
'frame',
|
|
11
|
-
];
|
|
12
|
-
|
|
13
|
-
export default class TimeCodeDisplay {// displays and renders smpte timecodes
|
|
6
|
+
const timeCodeNodeNames = ['hours', 'minutes', 'seconds', 'frame'];
|
|
7
|
+
|
|
8
|
+
export default class TimeCodeDisplay {
|
|
9
|
+
// displays and renders smpte timecodes
|
|
14
10
|
constructor(props) {
|
|
15
11
|
this.props = props;
|
|
16
12
|
|
|
@@ -21,7 +17,7 @@ export default class TimeCodeDisplay {// displays and renders smpte timecodes
|
|
|
21
17
|
const classNames = [
|
|
22
18
|
'vdt-timecode',
|
|
23
19
|
'vjs-time-control', // will apply default videojs style to the whole container, centers things vertically
|
|
24
|
-
|
|
20
|
+
!this.props.onInput ? 'duration' : '', // if no input capability, assume it's a duration timecode
|
|
25
21
|
];
|
|
26
22
|
this.container = document.createElement('div');
|
|
27
23
|
this.container.className = classNames.join(' ');
|
|
@@ -34,7 +30,8 @@ export default class TimeCodeDisplay {// displays and renders smpte timecodes
|
|
|
34
30
|
node.className = nodeName;
|
|
35
31
|
node.tabIndex = -1; // prevent default Tab behaviour for cycling inputs
|
|
36
32
|
|
|
37
|
-
if (this.props.onInput) {
|
|
33
|
+
if (this.props.onInput) {
|
|
34
|
+
// optional input capabilities
|
|
38
35
|
node.maxLength = 2;
|
|
39
36
|
|
|
40
37
|
node.onfocus = (e) => {
|
|
@@ -63,17 +60,16 @@ export default class TimeCodeDisplay {// displays and renders smpte timecodes
|
|
|
63
60
|
|
|
64
61
|
this.nodes[nodeName] = node;
|
|
65
62
|
|
|
66
|
-
|
|
67
63
|
const colon = document.createElement('span');
|
|
68
64
|
colon.innerHTML = ':';
|
|
69
65
|
|
|
70
|
-
|
|
71
66
|
this.container.appendChild(node);
|
|
72
|
-
|
|
67
|
+
index !== this.nodeNames.length - 1 && this.container.appendChild(colon);
|
|
73
68
|
});
|
|
74
69
|
|
|
75
70
|
if (this.props.target) {
|
|
76
|
-
if (this.props.appendAfter) {
|
|
71
|
+
if (this.props.appendAfter) {
|
|
72
|
+
// so it's possible to append after volume control, for example
|
|
77
73
|
this.props.target.parentNode.insertBefore(this.container, this.props.target.nextSibling);
|
|
78
74
|
} else {
|
|
79
75
|
this.props.target.appendChild(this.container);
|
|
@@ -87,13 +83,20 @@ export default class TimeCodeDisplay {// displays and renders smpte timecodes
|
|
|
87
83
|
}
|
|
88
84
|
}
|
|
89
85
|
|
|
90
|
-
update(valuesObj) {
|
|
86
|
+
update(valuesObj) {
|
|
87
|
+
// Object.keys and array.forEach are too slow, classic for is faster
|
|
91
88
|
const startCount = this.nodeNames.length - 1;
|
|
92
89
|
let i;
|
|
93
|
-
for (i = startCount; i > -1; i--) {
|
|
90
|
+
for (i = startCount; i > -1; i--) {
|
|
91
|
+
// updates follow frame -> seconds -> minutes -> hours order
|
|
94
92
|
const key = this.nodeNames[i];
|
|
95
93
|
|
|
96
|
-
if (
|
|
94
|
+
if (
|
|
95
|
+
typeof valuesObj[key] !== 'undefined' &&
|
|
96
|
+
valuesObj[key] !== parseInt(this.nodes[key].value, 10) &&
|
|
97
|
+
key !== this.state.selectedNode
|
|
98
|
+
) {
|
|
99
|
+
// re-render node if value is defineed and is different from current value
|
|
97
100
|
const str = valuesObj[key].toString();
|
|
98
101
|
this.nodes[key].value = this.toDigitPairStr(str);
|
|
99
102
|
}
|
|
@@ -126,7 +129,7 @@ export default class TimeCodeDisplay {// displays and renders smpte timecodes
|
|
|
126
129
|
}
|
|
127
130
|
|
|
128
131
|
toDigitPairStr(strValue) {
|
|
129
|
-
return
|
|
132
|
+
return strValue.length < 2 ? `0${strValue}` : strValue;
|
|
130
133
|
}
|
|
131
134
|
|
|
132
135
|
handleTimeCodeInput(e, nodeName) {
|
|
@@ -136,12 +139,13 @@ export default class TimeCodeDisplay {// displays and renders smpte timecodes
|
|
|
136
139
|
case 'Enter': // do work before submitting input
|
|
137
140
|
this.checkAndNormalizeAllInputs();
|
|
138
141
|
|
|
139
|
-
this.props.onInput &&
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
142
|
+
this.props.onInput &&
|
|
143
|
+
this.props.onInput(e, nodeName, {
|
|
144
|
+
hours: this.hours,
|
|
145
|
+
minutes: this.minutes,
|
|
146
|
+
seconds: this.seconds,
|
|
147
|
+
frame: this.frame,
|
|
148
|
+
});
|
|
145
149
|
|
|
146
150
|
this[nodeName] = e.currentTarget.value;
|
|
147
151
|
e.currentTarget.blur(); // done
|
|
@@ -151,12 +155,12 @@ export default class TimeCodeDisplay {// displays and renders smpte timecodes
|
|
|
151
155
|
|
|
152
156
|
// tab trough inputs in a loop fashion
|
|
153
157
|
if (!e.shiftKey) {
|
|
154
|
-
if (
|
|
158
|
+
if (nodeIndex + 1 <= this.nodeNames.length - 1) {
|
|
155
159
|
this.nodes[this.nodeNames[nodeIndex + 1]].focus(); // focus next
|
|
156
160
|
} else {
|
|
157
161
|
this.nodes[this.nodeNames[0]].focus(); // focus first
|
|
158
162
|
}
|
|
159
|
-
} else if (
|
|
163
|
+
} else if (nodeIndex - 1 >= 0) {
|
|
160
164
|
this.nodes[this.nodeNames[nodeIndex - 1]].focus(); // focus previous
|
|
161
165
|
} else {
|
|
162
166
|
this.nodes[this.nodeNames[this.nodeNames.length - 1]].focus(); // focus last
|
|
@@ -180,7 +184,8 @@ export default class TimeCodeDisplay {// displays and renders smpte timecodes
|
|
|
180
184
|
if (this.nodes[nodeName].value.length === 2 && !isNaN(e.key)) {
|
|
181
185
|
const nodeIndex = this.nodeNames.indexOf(nodeName); // determine position in timecode
|
|
182
186
|
|
|
183
|
-
if (
|
|
187
|
+
if (nodeIndex + 1 <= this.nodeNames.length - 1) {
|
|
188
|
+
// check bounds
|
|
184
189
|
this.nodes[this.nodeNames[nodeIndex + 1]].focus(); // focus next
|
|
185
190
|
}
|
|
186
191
|
}
|
|
@@ -188,7 +193,8 @@ export default class TimeCodeDisplay {// displays and renders smpte timecodes
|
|
|
188
193
|
|
|
189
194
|
checkAndNormalizeAllInputs() {
|
|
190
195
|
this.nodeNames.forEach((nodeName) => {
|
|
191
|
-
if (this.nodes[nodeName].value.length < 1) {
|
|
196
|
+
if (this.nodes[nodeName].value.length < 1) {
|
|
197
|
+
// somebody left the input blank
|
|
192
198
|
this.nodes[nodeName].value = '00';
|
|
193
199
|
}
|
|
194
200
|
|
|
@@ -244,12 +250,14 @@ export default class TimeCodeDisplay {// displays and renders smpte timecodes
|
|
|
244
250
|
};
|
|
245
251
|
}
|
|
246
252
|
|
|
247
|
-
set
|
|
253
|
+
set smpte(o) {
|
|
248
254
|
this.update(o);
|
|
249
255
|
}
|
|
250
256
|
|
|
251
257
|
get smpteString() {
|
|
252
|
-
return `${this.getFormatted('hours')}:${this.getFormatted('minutes')}:${this.getFormatted(
|
|
258
|
+
return `${this.getFormatted('hours')}:${this.getFormatted('minutes')}:${this.getFormatted(
|
|
259
|
+
'seconds',
|
|
260
|
+
)}:${this.getFormatted('frame')}`;
|
|
253
261
|
}
|
|
254
262
|
|
|
255
263
|
set external(bool) {
|
|
@@ -261,6 +269,6 @@ export default class TimeCodeDisplay {// displays and renders smpte timecodes
|
|
|
261
269
|
}
|
|
262
270
|
|
|
263
271
|
get external() {
|
|
264
|
-
return
|
|
272
|
+
return this.container.classList.contains('external');
|
|
265
273
|
}
|
|
266
274
|
}
|
package/src/videoTime.js
CHANGED
|
@@ -36,10 +36,10 @@ class VideoTime {
|
|
|
36
36
|
|
|
37
37
|
smpteToCurrentTimeFromStart(values) {
|
|
38
38
|
return (
|
|
39
|
-
values.hours * 3600
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
values.hours * 3600 +
|
|
40
|
+
values.minutes * 60 +
|
|
41
|
+
values.seconds +
|
|
42
|
+
values.frame / this.props.frameRate
|
|
43
43
|
);
|
|
44
44
|
}
|
|
45
45
|
|