@gcorevideo/player 2.21.4 → 2.22.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/assets/dvr-controls/dvr_controls.scss +7 -25
- package/assets/dvr-controls/index.ejs +2 -2
- package/assets/media-control/media-control.ejs +1 -1
- package/assets/media-control/media-control.scss +8 -3
- package/assets/media-control/width370.scss +1 -1
- package/assets/style/theme.scss +1 -1
- package/dist/core.js +1 -1
- package/dist/index.css +1441 -1446
- package/dist/index.js +82 -79
- package/dist/plugins/index.css +1189 -1194
- package/dist/plugins/index.js +81 -76
- package/lib/plugins/dvr-controls/DvrControls.d.ts +0 -3
- package/lib/plugins/dvr-controls/DvrControls.d.ts.map +1 -1
- package/lib/plugins/dvr-controls/DvrControls.js +13 -38
- package/lib/plugins/media-control/MediaControl.d.ts +10 -14
- package/lib/plugins/media-control/MediaControl.d.ts.map +1 -1
- package/lib/plugins/media-control/MediaControl.js +66 -38
- package/lib/testUtils.d.ts +4 -1
- package/lib/testUtils.d.ts.map +1 -1
- package/lib/testUtils.js +10 -11
- package/package.json +1 -1
- package/src/plugins/dvr-controls/DvrControls.ts +16 -44
- package/src/plugins/dvr-controls/__tests__/DvrControls.test.ts +23 -25
- package/src/plugins/dvr-controls/__tests__/__snapshots__/DvrControls.test.ts.snap +8 -32
- package/src/plugins/media-control/MediaControl.ts +91 -51
- package/src/plugins/media-control/__tests__/MediaControl.test.ts +89 -0
- package/src/plugins/media-control/__tests__/__snapshots__/MediaControl.test.ts.snap +128 -0
- package/src/testUtils.ts +10 -11
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -19,6 +19,12 @@ import volumeMaxIcon from '../../../assets/icons/new/volume-max.svg';
|
|
|
19
19
|
import volumeOffIcon from '../../../assets/icons/new/volume-off.svg';
|
|
20
20
|
import fullscreenOffIcon from '../../../assets/icons/new/fullscreen-off.svg';
|
|
21
21
|
import fullscreenOnIcon from '../../../assets/icons/new/fullscreen-on.svg';
|
|
22
|
+
const DEFAULT_SETTINGS = {
|
|
23
|
+
left: [],
|
|
24
|
+
right: [],
|
|
25
|
+
default: [],
|
|
26
|
+
seekEnabled: true,
|
|
27
|
+
};
|
|
22
28
|
/**
|
|
23
29
|
* Custom events emitted by the plugins to communicate with one another
|
|
24
30
|
* @beta
|
|
@@ -34,7 +40,8 @@ const T = 'plugins.media_control';
|
|
|
34
40
|
const LEFT_ORDER = [
|
|
35
41
|
'playpause',
|
|
36
42
|
'playstop',
|
|
37
|
-
'live',
|
|
43
|
+
// 'live',
|
|
44
|
+
'dvr',
|
|
38
45
|
'volume',
|
|
39
46
|
'position',
|
|
40
47
|
'duration',
|
|
@@ -68,14 +75,13 @@ export class MediaControl extends UICorePlugin {
|
|
|
68
75
|
hideId = null;
|
|
69
76
|
hideVolumeId = null;
|
|
70
77
|
intendedVolume = 100;
|
|
71
|
-
isHD = false;
|
|
72
78
|
keepVisible = false;
|
|
73
79
|
kibo;
|
|
74
80
|
lastMouseX = 0;
|
|
75
81
|
lastMouseY = 0;
|
|
76
82
|
persistConfig;
|
|
77
83
|
rendered = false;
|
|
78
|
-
settings =
|
|
84
|
+
settings = DEFAULT_SETTINGS;
|
|
79
85
|
userDisabled = false;
|
|
80
86
|
userKeepVisible = false;
|
|
81
87
|
verticalVolume = false;
|
|
@@ -219,8 +225,6 @@ export class MediaControl extends UICorePlugin {
|
|
|
219
225
|
* @internal
|
|
220
226
|
*/
|
|
221
227
|
bindEvents() {
|
|
222
|
-
// @ts-ignore
|
|
223
|
-
this.stopListening();
|
|
224
228
|
this.listenTo(this.core, Events.CORE_ACTIVE_CONTAINER_CHANGED, this.onActiveContainerChanged);
|
|
225
229
|
this.listenTo(this.core, Events.CORE_MOUSE_MOVE, this.show);
|
|
226
230
|
this.listenTo(this.core, Events.CORE_MOUSE_LEAVE, () => this.hide(this.options.hideMediaControlDelay));
|
|
@@ -257,8 +261,8 @@ export class MediaControl extends UICorePlugin {
|
|
|
257
261
|
this.listenTo(this.core.activeContainer, Events.CONTAINER_TIMEUPDATE, this.onTimeUpdate);
|
|
258
262
|
this.listenTo(this.core.activeContainer, Events.CONTAINER_PROGRESS, this.updateProgressBar);
|
|
259
263
|
this.listenTo(this.core.activeContainer, Events.CONTAINER_SETTINGSUPDATE, this.updateSettings);
|
|
260
|
-
this.listenTo(this.core.activeContainer, Events.CONTAINER_PLAYBACKDVRSTATECHANGED, this.
|
|
261
|
-
this.listenTo(this.core.activeContainer, Events.CONTAINER_HIGHDEFINITIONUPDATE, this.
|
|
264
|
+
this.listenTo(this.core.activeContainer, Events.CONTAINER_PLAYBACKDVRSTATECHANGED, this.onDvrStateChanged);
|
|
265
|
+
this.listenTo(this.core.activeContainer, Events.CONTAINER_HIGHDEFINITIONUPDATE, this.onHdUpdate);
|
|
262
266
|
this.listenTo(this.core.activeContainer, Events.CONTAINER_MEDIACONTROL_DISABLE, this.disable);
|
|
263
267
|
this.listenTo(this.core.activeContainer, Events.CONTAINER_MEDIACONTROL_ENABLE, this.enable);
|
|
264
268
|
this.listenTo(this.core.activeContainer, Events.CONTAINER_ENDED, this.ended);
|
|
@@ -306,7 +310,13 @@ export class MediaControl extends UICorePlugin {
|
|
|
306
310
|
// see https://github.com/clappr/clappr/issues/1127
|
|
307
311
|
if (!Fullscreen.fullscreenEnabled() && video.webkitSupportsFullscreen) {
|
|
308
312
|
this.fullScreenOnVideoTagSupported = true;
|
|
309
|
-
|
|
313
|
+
}
|
|
314
|
+
this.updateSettings();
|
|
315
|
+
if (this.core.activeContainer.getPlaybackType() === Playback.LIVE) {
|
|
316
|
+
this.$el.addClass('live');
|
|
317
|
+
}
|
|
318
|
+
else {
|
|
319
|
+
this.$el.removeClass('live');
|
|
310
320
|
}
|
|
311
321
|
}
|
|
312
322
|
updateVolumeUI() {
|
|
@@ -315,8 +325,6 @@ export class MediaControl extends UICorePlugin {
|
|
|
315
325
|
return;
|
|
316
326
|
}
|
|
317
327
|
assert.ok(this.$volumeBarContainer, 'volume bar container must be present');
|
|
318
|
-
// update volume bar scrubber/fill on bar mode
|
|
319
|
-
// this.$volumeBarContainer.find('.bar-fill-2').css({});
|
|
320
328
|
const containerWidth = this.$volumeBarContainer.width();
|
|
321
329
|
assert.ok(this.$volumeBarBackground, 'volume bar background must be present');
|
|
322
330
|
const barWidth = this.$volumeBarBackground.width();
|
|
@@ -505,17 +513,18 @@ export class MediaControl extends UICorePlugin {
|
|
|
505
513
|
// if the container is not ready etc
|
|
506
514
|
this.intendedVolume = value;
|
|
507
515
|
this.persistConfig && !isInitialVolume && Config.persist('volume', value);
|
|
516
|
+
// TODO
|
|
508
517
|
const setWhenContainerReady = () => {
|
|
509
|
-
if (this.
|
|
510
|
-
this.
|
|
518
|
+
if (this.core.activeContainer && this.core.activeContainer.isReady) {
|
|
519
|
+
this.core.activeContainer.setVolume(value);
|
|
511
520
|
}
|
|
512
521
|
else {
|
|
513
|
-
this.listenToOnce(this.
|
|
514
|
-
this.
|
|
522
|
+
this.listenToOnce(this.core.activeContainer, Events.CONTAINER_READY, () => {
|
|
523
|
+
this.core.activeContainer.setVolume(value);
|
|
515
524
|
});
|
|
516
525
|
}
|
|
517
526
|
};
|
|
518
|
-
if (!this.
|
|
527
|
+
if (!this.core.activeContainer) {
|
|
519
528
|
this.listenToOnce(this, Events.MEDIACONTROL_CONTAINERCHANGED, () => setWhenContainerReady());
|
|
520
529
|
}
|
|
521
530
|
else {
|
|
@@ -525,7 +534,7 @@ export class MediaControl extends UICorePlugin {
|
|
|
525
534
|
toggleFullscreen() {
|
|
526
535
|
if (!Browser.isMobile) {
|
|
527
536
|
this.trigger(Events.MEDIACONTROL_FULLSCREEN, this.name);
|
|
528
|
-
this.
|
|
537
|
+
this.core.activeContainer.fullscreen();
|
|
529
538
|
this.core.toggleFullscreen();
|
|
530
539
|
this.resetUserKeepVisible();
|
|
531
540
|
}
|
|
@@ -537,6 +546,7 @@ export class MediaControl extends UICorePlugin {
|
|
|
537
546
|
this.changeTogglePlay();
|
|
538
547
|
this.bindContainerEvents();
|
|
539
548
|
this.updateSettings();
|
|
549
|
+
// TODO remove
|
|
540
550
|
this.core.activeContainer.trigger(Events.CONTAINER_PLAYBACKDVRSTATECHANGED, this.core.activeContainer.isDvrInUse());
|
|
541
551
|
// TODO test
|
|
542
552
|
if (this.core.activeContainer.mediaControlDisabled) {
|
|
@@ -561,7 +571,9 @@ export class MediaControl extends UICorePlugin {
|
|
|
561
571
|
seekTimePlugin?.$el.find('span').addClass('gcore-skin-text-color');
|
|
562
572
|
}
|
|
563
573
|
showVolumeBar() {
|
|
564
|
-
|
|
574
|
+
if (this.hideVolumeId) {
|
|
575
|
+
clearTimeout(this.hideVolumeId);
|
|
576
|
+
}
|
|
565
577
|
this.$volumeBarContainer?.removeClass('volume-bar-hide');
|
|
566
578
|
}
|
|
567
579
|
hideVolumeBar(timeout = 400) {
|
|
@@ -607,9 +619,9 @@ export class MediaControl extends UICorePlugin {
|
|
|
607
619
|
}
|
|
608
620
|
// default to 100%
|
|
609
621
|
this.currentSeekBarPercentage = 100;
|
|
610
|
-
if (this.
|
|
611
|
-
(this.
|
|
612
|
-
this.
|
|
622
|
+
if (this.core.activeContainer &&
|
|
623
|
+
(this.core.activeContainer.getPlaybackType() !== Playback.LIVE ||
|
|
624
|
+
this.core.activeContainer.isDvrInUse())) {
|
|
613
625
|
this.currentSeekBarPercentage =
|
|
614
626
|
(this.currentPositionValue / this.currentDurationValue) * 100;
|
|
615
627
|
}
|
|
@@ -636,16 +648,10 @@ export class MediaControl extends UICorePlugin {
|
|
|
636
648
|
const offsetX = MediaControl.getPageX(event) - this.$seekBarContainer.offset().left;
|
|
637
649
|
let pos = (offsetX / this.$seekBarContainer.width()) * 100;
|
|
638
650
|
pos = Math.min(100, Math.max(pos, 0));
|
|
639
|
-
this.
|
|
651
|
+
this.core.activeContainer && this.core.activeContainer.seekPercentage(pos);
|
|
640
652
|
this.setSeekPercentage(pos);
|
|
641
653
|
return false;
|
|
642
654
|
}
|
|
643
|
-
setKeepVisible() {
|
|
644
|
-
this.keepVisible = true;
|
|
645
|
-
}
|
|
646
|
-
resetKeepVisible() {
|
|
647
|
-
this.keepVisible = false;
|
|
648
|
-
}
|
|
649
655
|
setUserKeepVisible() {
|
|
650
656
|
this.userKeepVisible = true;
|
|
651
657
|
}
|
|
@@ -723,7 +729,12 @@ export class MediaControl extends UICorePlugin {
|
|
|
723
729
|
default: [],
|
|
724
730
|
right: [],
|
|
725
731
|
}, this.core.activeContainer.settings);
|
|
732
|
+
// TODO make order controlled via CSS
|
|
726
733
|
newSettings.left = orderByOrderPattern([...newSettings.left, 'clipsText', 'volume'], LEFT_ORDER);
|
|
734
|
+
if (this.core.activePlayback.getPlaybackType() === Playback.LIVE &&
|
|
735
|
+
this.core.activePlayback.dvrEnabled) {
|
|
736
|
+
newSettings.left.push('dvr');
|
|
737
|
+
}
|
|
727
738
|
// actual order of the items appear rendered is controlled by CSS
|
|
728
739
|
newSettings.right = [
|
|
729
740
|
'fullscreen',
|
|
@@ -745,17 +756,18 @@ export class MediaControl extends UICorePlugin {
|
|
|
745
756
|
}
|
|
746
757
|
removeArrayItem(newSettings.default, 'hd-indicator');
|
|
747
758
|
removeArrayItem(newSettings.left, 'hd-indicator');
|
|
759
|
+
// TODO get from container's settings
|
|
748
760
|
if (this.core.activePlayback.name === 'html5_video') {
|
|
749
761
|
newSettings.seekEnabled = this.isSeekEnabledForHtml5Playback();
|
|
750
762
|
}
|
|
751
|
-
const settingsChanged =
|
|
763
|
+
const settingsChanged = serializeSettings(this.settings) !== serializeSettings(newSettings);
|
|
752
764
|
if (settingsChanged) {
|
|
753
765
|
this.settings = newSettings;
|
|
754
766
|
this.render();
|
|
755
767
|
}
|
|
756
768
|
}
|
|
757
|
-
|
|
758
|
-
|
|
769
|
+
onHdUpdate(isHD) {
|
|
770
|
+
// TODO render?
|
|
759
771
|
}
|
|
760
772
|
createCachedElements() {
|
|
761
773
|
const $layer = this.$el.find('.media-control-layer');
|
|
@@ -818,7 +830,7 @@ export class MediaControl extends UICorePlugin {
|
|
|
818
830
|
trace(`${T} putElement`, { name, panel: !!panel });
|
|
819
831
|
if (panel) {
|
|
820
832
|
const current = panel.find(`[data-${name}]`);
|
|
821
|
-
element.setAttribute(`data-${name}`,
|
|
833
|
+
element.setAttribute(`data-${name}`, '');
|
|
822
834
|
// TODO test
|
|
823
835
|
if (current.length) {
|
|
824
836
|
if (current[0] === element) {
|
|
@@ -832,16 +844,16 @@ export class MediaControl extends UICorePlugin {
|
|
|
832
844
|
}
|
|
833
845
|
}
|
|
834
846
|
/**
|
|
835
|
-
*
|
|
836
|
-
* @
|
|
847
|
+
* Toggle the visibility of a media control element
|
|
848
|
+
* @param name - The name of the media control element
|
|
849
|
+
* @param show - Whether to show or hide the element
|
|
837
850
|
*/
|
|
851
|
+
toggleElement(name, show) {
|
|
852
|
+
this.$el.find(`[data-${name}]`).toggle(show);
|
|
853
|
+
}
|
|
838
854
|
getRightPanel() {
|
|
839
855
|
return this.$el.find('.media-control-right-panel');
|
|
840
856
|
}
|
|
841
|
-
/**
|
|
842
|
-
* Get the left panel area to append custom elements to
|
|
843
|
-
* @returns ZeptoSelector of the left panel element
|
|
844
|
-
*/
|
|
845
857
|
getLeftPanel() {
|
|
846
858
|
return this.$el.find('.media-control-left-panel');
|
|
847
859
|
}
|
|
@@ -1040,7 +1052,6 @@ export class MediaControl extends UICorePlugin {
|
|
|
1040
1052
|
this.hideVolumeBar(0);
|
|
1041
1053
|
}, 0);
|
|
1042
1054
|
this.parseColors();
|
|
1043
|
-
this.highDefinitionUpdate(this.isHD);
|
|
1044
1055
|
this.core.$el.append(this.el);
|
|
1045
1056
|
this.rendered = true;
|
|
1046
1057
|
this.updateVolumeUI();
|
|
@@ -1127,7 +1138,24 @@ export class MediaControl extends UICorePlugin {
|
|
|
1127
1138
|
}
|
|
1128
1139
|
return null;
|
|
1129
1140
|
}
|
|
1141
|
+
onDvrStateChanged(dvrInUse) {
|
|
1142
|
+
if (dvrInUse) {
|
|
1143
|
+
this.$el.addClass('dvr');
|
|
1144
|
+
}
|
|
1145
|
+
else {
|
|
1146
|
+
this.$el.removeClass('dvr');
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1130
1149
|
}
|
|
1131
1150
|
MediaControl.extend = function (properties) {
|
|
1132
1151
|
return extend(MediaControl, properties);
|
|
1133
1152
|
};
|
|
1153
|
+
function serializeSettings(s) {
|
|
1154
|
+
return s.left
|
|
1155
|
+
.slice()
|
|
1156
|
+
.sort()
|
|
1157
|
+
.concat(s.right.slice().sort())
|
|
1158
|
+
.concat(s.default.slice().sort())
|
|
1159
|
+
.concat([s.seekEnabled])
|
|
1160
|
+
.join(',');
|
|
1161
|
+
}
|
package/lib/testUtils.d.ts
CHANGED
|
@@ -65,7 +65,9 @@ export declare function createSpinnerPlugin(): Events<string | symbol, any> & {
|
|
|
65
65
|
export declare function createMockPlayback(name?: string): Events<string | symbol, any> & {
|
|
66
66
|
name: string;
|
|
67
67
|
currentLevel: number;
|
|
68
|
+
el: HTMLVideoElement;
|
|
68
69
|
dvrEnabled: boolean;
|
|
70
|
+
dvrInUse: boolean;
|
|
69
71
|
levels: never[];
|
|
70
72
|
consent(): void;
|
|
71
73
|
play(): void;
|
|
@@ -92,13 +94,14 @@ export declare function createMockPlayback(name?: string): Events<string | symbo
|
|
|
92
94
|
trigger: <T extends string | symbol>(event: T, ...args: any[]) => boolean;
|
|
93
95
|
};
|
|
94
96
|
export declare function createMockContainer(playback?: any): Events<string | symbol, any> & {
|
|
95
|
-
el:
|
|
97
|
+
el: any;
|
|
96
98
|
playback: any;
|
|
97
99
|
$el: any;
|
|
98
100
|
getDuration: import("vitest").Mock<(...args: any[]) => any>;
|
|
99
101
|
getPlugin: import("vitest").Mock<(...args: any[]) => any>;
|
|
100
102
|
getPlaybackType: import("vitest").Mock<(...args: any[]) => any>;
|
|
101
103
|
isDvrInUse: import("vitest").Mock<(...args: any[]) => any>;
|
|
104
|
+
isDvrEnabled: import("vitest").Mock<(...args: any[]) => any>;
|
|
102
105
|
isPlaying: import("vitest").Mock<(...args: any[]) => any>;
|
|
103
106
|
play: import("vitest").Mock<(...args: any[]) => any>;
|
|
104
107
|
seek: import("vitest").Mock<(...args: any[]) => any>;
|
package/lib/testUtils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testUtils.d.ts","sourceRoot":"","sources":["../src/testUtils.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"testUtils.d.ts","sourceRoot":"","sources":["../src/testUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,YAAY,EAAE,MAAM,cAAc,CAAA;AACxD,OAAO,MAAM,MAAM,eAAe,CAAA;AAElC;;;;GAIG;AACH,qBAAa,aAAc,SAAQ,MAAM;IAErC,SAAS,CAAC,OAAO,EAAE,GAAG;IACtB,QAAQ,CAAC,IAAI,EAAE,GAAG;IAClB,SAAS,CAAC,WAAW,CAAC,EAAE,GAAG;gBAFjB,OAAO,EAAE,GAAG,EACb,IAAI,EAAE,GAAG,EACR,WAAW,CAAC,EAAE,GAAG,YAAA;IAK7B,IAAI,IAAI,WAEP;IAED,OAAO;IAEP,IAAI;IAEJ,KAAK;IAEL,IAAI;IAEJ,OAAO;IAEP,IAAI;IAEJ,cAAc;IAEd,WAAW;IAIX,QAAQ;IAER,OAAO;IAEP,eAAe;IAIf,kBAAkB;IAIlB,cAAc;IAId,qBAAqB;IAIrB,IAAI;IAEJ,MAAM;IAEN,MAAM;IAEN,SAAS;IAET,eAAe;IAIf,WAAW;IAIX,QAAQ;IAIR,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE;CAGtC;AAED,wBAAgB,cAAc,CAC5B,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACrC,SAAS,GAAE,GAA2B;;;;;;;;;;;;;;;;EAqBvC;AAED,wBAAgB,gBAAgB;;;EAK/B;AAED,wBAAgB,mBAAmB;;;;;;EAKlC;AAED,wBAAgB,kBAAkB,CAAC,IAAI,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiC/C;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,GAAE,GAA0B;;;;;;;;;;;;;EAiBvE;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,GAAG,gBAiB/C"}
|
package/lib/testUtils.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $, UICorePlugin } from '@clappr/core';
|
|
1
|
+
import { $, Playback, UICorePlugin } from '@clappr/core';
|
|
2
2
|
import Events from 'eventemitter3';
|
|
3
3
|
import { vi } from 'vitest';
|
|
4
4
|
/**
|
|
@@ -32,7 +32,7 @@ export class _MockPlayback extends Events {
|
|
|
32
32
|
enterPiP() { }
|
|
33
33
|
exitPiP() { }
|
|
34
34
|
getPlaybackType() {
|
|
35
|
-
return
|
|
35
|
+
return Playback.LIVE;
|
|
36
36
|
}
|
|
37
37
|
getStartTimeOffset() {
|
|
38
38
|
return 0;
|
|
@@ -75,7 +75,7 @@ export function createMockCore(options = {}, container = createMockContainer())
|
|
|
75
75
|
...options,
|
|
76
76
|
},
|
|
77
77
|
configure: vi.fn(),
|
|
78
|
-
getPlaybackType: vi.fn(),
|
|
78
|
+
getPlaybackType: vi.fn().mockReturnValue(Playback.LIVE),
|
|
79
79
|
getPlugin: vi.fn(),
|
|
80
80
|
load: vi.fn(),
|
|
81
81
|
trigger: emitter.emit,
|
|
@@ -98,7 +98,9 @@ export function createMockPlayback(name = 'mock') {
|
|
|
98
98
|
return Object.assign(emitter, {
|
|
99
99
|
name,
|
|
100
100
|
currentLevel: -1,
|
|
101
|
+
el: document.createElement('video'),
|
|
101
102
|
dvrEnabled: false,
|
|
103
|
+
dvrInUse: false,
|
|
102
104
|
levels: [],
|
|
103
105
|
consent() { },
|
|
104
106
|
play() { },
|
|
@@ -110,7 +112,7 @@ export function createMockPlayback(name = 'mock') {
|
|
|
110
112
|
getDuration: vi.fn().mockImplementation(() => 100),
|
|
111
113
|
enterPiP: vi.fn(),
|
|
112
114
|
exitPiP: vi.fn(),
|
|
113
|
-
getPlaybackType: vi.fn().mockImplementation(() =>
|
|
115
|
+
getPlaybackType: vi.fn().mockImplementation(() => Playback.LIVE),
|
|
114
116
|
getStartTimeOffset: vi.fn().mockImplementation(() => 0),
|
|
115
117
|
getCurrentTime: vi.fn().mockImplementation(() => 0),
|
|
116
118
|
isHighDefinitionInUse: vi.fn().mockImplementation(() => false),
|
|
@@ -126,7 +128,7 @@ export function createMockPlayback(name = 'mock') {
|
|
|
126
128
|
});
|
|
127
129
|
}
|
|
128
130
|
export function createMockContainer(playback = createMockPlayback()) {
|
|
129
|
-
const el =
|
|
131
|
+
const el = playback.el;
|
|
130
132
|
const emitter = new Events();
|
|
131
133
|
return Object.assign(emitter, {
|
|
132
134
|
el,
|
|
@@ -134,8 +136,9 @@ export function createMockContainer(playback = createMockPlayback()) {
|
|
|
134
136
|
$el: $(el),
|
|
135
137
|
getDuration: vi.fn().mockReturnValue(0),
|
|
136
138
|
getPlugin: vi.fn(),
|
|
137
|
-
getPlaybackType: vi.fn().mockReturnValue(
|
|
139
|
+
getPlaybackType: vi.fn().mockReturnValue(Playback.LIVE),
|
|
138
140
|
isDvrInUse: vi.fn().mockReturnValue(false),
|
|
141
|
+
isDvrEnabled: vi.fn().mockReturnValue(false),
|
|
139
142
|
isPlaying: vi.fn().mockReturnValue(false),
|
|
140
143
|
play: vi.fn(),
|
|
141
144
|
seek: vi.fn(),
|
|
@@ -155,10 +158,6 @@ export function createMockMediaControl(core) {
|
|
|
155
158
|
// @ts-ignore
|
|
156
159
|
mediaControl.putElement = vi.fn();
|
|
157
160
|
// @ts-ignore
|
|
158
|
-
mediaControl.
|
|
159
|
-
// @ts-ignore
|
|
160
|
-
mediaControl.getRightPanel = vi.fn().mockImplementation(() => mediaControl.$el.find('.media-control-right-panel'));
|
|
161
|
-
// @ts-ignore
|
|
162
|
-
mediaControl.getCenterPanel = vi.fn().mockImplementation(() => mediaControl.$el.find('.media-control-center-panel'));
|
|
161
|
+
mediaControl.toggleElement = vi.fn();
|
|
163
162
|
return mediaControl;
|
|
164
163
|
}
|
package/package.json
CHANGED
|
@@ -56,7 +56,6 @@ export class DvrControls extends UICorePlugin {
|
|
|
56
56
|
override get attributes() {
|
|
57
57
|
return {
|
|
58
58
|
class: 'dvr-controls',
|
|
59
|
-
'data-dvr-controls': '',
|
|
60
59
|
}
|
|
61
60
|
}
|
|
62
61
|
|
|
@@ -65,7 +64,6 @@ export class DvrControls extends UICorePlugin {
|
|
|
65
64
|
*/
|
|
66
65
|
override bindEvents() {
|
|
67
66
|
this.listenTo(this.core, Events.CORE_READY, this.onCoreReady)
|
|
68
|
-
this.listenTo(this.core, Events.CORE_OPTIONS_CHANGE, this.render)
|
|
69
67
|
this.listenTo(
|
|
70
68
|
this.core,
|
|
71
69
|
Events.CORE_ACTIVE_CONTAINER_CHANGED,
|
|
@@ -76,48 +74,23 @@ export class DvrControls extends UICorePlugin {
|
|
|
76
74
|
private onCoreReady() {
|
|
77
75
|
const mediaControl = this.core.getPlugin('media_control')
|
|
78
76
|
assert(mediaControl, 'media_control plugin is required')
|
|
77
|
+
|
|
79
78
|
this.listenTo(
|
|
80
79
|
mediaControl,
|
|
81
80
|
Events.MEDIACONTROL_RENDERED,
|
|
82
|
-
this.
|
|
81
|
+
this.render,
|
|
83
82
|
)
|
|
84
|
-
|
|
83
|
+
// MediaControl has been rendered
|
|
84
|
+
this.render()
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
private bindContainerEvents() {
|
|
88
|
+
trace(`${T} bindContainerEvents`)
|
|
88
89
|
this.listenToOnce(
|
|
89
90
|
this.core.activeContainer,
|
|
90
91
|
Events.CONTAINER_TIMEUPDATE,
|
|
91
92
|
this.render,
|
|
92
93
|
)
|
|
93
|
-
this.listenTo(
|
|
94
|
-
this.core.activeContainer,
|
|
95
|
-
Events.CONTAINER_PLAYBACKDVRSTATECHANGED,
|
|
96
|
-
this.onDvrChanged,
|
|
97
|
-
)
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
private onDvrChanged(dvrInUse: boolean) {
|
|
101
|
-
trace(`${T} onDvrChanged`, {
|
|
102
|
-
dvrInUse,
|
|
103
|
-
})
|
|
104
|
-
if (this.core.getPlaybackType() !== Playback.LIVE) {
|
|
105
|
-
return
|
|
106
|
-
}
|
|
107
|
-
this.render()
|
|
108
|
-
const mediaControl = this.core.getPlugin('media_control')
|
|
109
|
-
mediaControl.$el.addClass('live')
|
|
110
|
-
if (dvrInUse) {
|
|
111
|
-
mediaControl.$el
|
|
112
|
-
.addClass('dvr')
|
|
113
|
-
.find(
|
|
114
|
-
// TODO add API, test
|
|
115
|
-
'.media-control-indicator[data-position], .media-control-indicator[data-duration]',
|
|
116
|
-
)
|
|
117
|
-
.hide()
|
|
118
|
-
} else {
|
|
119
|
-
mediaControl.$el.removeClass('dvr')
|
|
120
|
-
}
|
|
121
94
|
}
|
|
122
95
|
|
|
123
96
|
private click() {
|
|
@@ -128,14 +101,8 @@ export class DvrControls extends UICorePlugin {
|
|
|
128
101
|
container.seek(container.getDuration())
|
|
129
102
|
}
|
|
130
103
|
|
|
131
|
-
private settingsUpdate() {
|
|
132
|
-
this.core.getPlugin('media_control').$el.removeClass('live')
|
|
133
|
-
this.render()
|
|
134
|
-
}
|
|
135
|
-
|
|
136
104
|
private shouldRender() {
|
|
137
|
-
|
|
138
|
-
return useDvrControls && this.core.getPlaybackType() === Playback.LIVE
|
|
105
|
+
return this.core.getPlaybackType() === Playback.LIVE
|
|
139
106
|
}
|
|
140
107
|
|
|
141
108
|
/**
|
|
@@ -146,18 +113,23 @@ export class DvrControls extends UICorePlugin {
|
|
|
146
113
|
dvrEnabled: this.core.activePlayback?.dvrEnabled,
|
|
147
114
|
playbackType: this.core.getPlaybackType(),
|
|
148
115
|
})
|
|
116
|
+
const mediaControl = this.core.getPlugin('media_control') as MediaControl
|
|
117
|
+
if (!mediaControl) {
|
|
118
|
+
return this
|
|
119
|
+
}
|
|
149
120
|
if (!this.shouldRender()) {
|
|
150
121
|
return this
|
|
151
122
|
}
|
|
123
|
+
|
|
124
|
+
mediaControl.toggleElement('duration', false)
|
|
125
|
+
mediaControl.toggleElement('position', false)
|
|
126
|
+
|
|
152
127
|
this.$el.html(
|
|
153
128
|
DvrControls.template({
|
|
154
|
-
|
|
155
|
-
backToLive: this.core.i18n.t('back_to_live'),
|
|
129
|
+
i18n: this.core.i18n,
|
|
156
130
|
}),
|
|
157
131
|
)
|
|
158
|
-
|
|
159
|
-
mediaControl.$el.addClass('live')
|
|
160
|
-
mediaControl.getLeftPanel().append(this.$el)
|
|
132
|
+
mediaControl.putElement('dvr', this.el)
|
|
161
133
|
|
|
162
134
|
return this
|
|
163
135
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
2
2
|
import { DvrControls } from '../DvrControls.js'
|
|
3
3
|
import { createMockCore, createMockMediaControl } from '../../../testUtils.js'
|
|
4
|
+
import { Events, Playback } from '@clappr/core'
|
|
4
5
|
// import { LogTracer, Logger, setTracer } from '@gcorevideo/utils'
|
|
5
6
|
|
|
6
7
|
// setTracer(new LogTracer('DvrControls.test'))
|
|
@@ -28,36 +29,29 @@ describe('DvrControls', () => {
|
|
|
28
29
|
describe.each([
|
|
29
30
|
['no DVR', false, false, false],
|
|
30
31
|
['DVR at live edge', true, false, false],
|
|
31
|
-
|
|
32
|
-
])('%s', (_, dvrEnabled, dvrInUse, indicateDvr) => {
|
|
32
|
+
])('%s', (_, dvrEnabled, dvrInUse) => {
|
|
33
33
|
beforeEach(() => {
|
|
34
34
|
core.activePlayback.dvrEnabled = dvrEnabled
|
|
35
|
-
core.
|
|
36
|
-
core.trigger(
|
|
35
|
+
core.activeContainer.isDvrEnabled.mockReturnValue(dvrEnabled)
|
|
36
|
+
core.trigger(Events.CORE_READY)
|
|
37
|
+
core.trigger(Events.CORE_ACTIVE_CONTAINER_CHANGED, core.activeContainer)
|
|
37
38
|
if (dvrInUse) {
|
|
38
|
-
core.
|
|
39
|
+
core.activePlayback.dvrInUse = true
|
|
40
|
+
core.activeContainer.isDvrInUse.mockReturnValue(true)
|
|
41
|
+
core.activeContainer.emit(Events.CONTAINER_PLAYBACKDVRSTATECHANGED, true)
|
|
39
42
|
}
|
|
40
43
|
})
|
|
41
44
|
it('should render', () => {
|
|
42
45
|
expect(dvrControls.el.textContent).toBeTruthy()
|
|
43
46
|
expect(dvrControls.el.innerHTML).toMatchSnapshot()
|
|
44
47
|
})
|
|
45
|
-
it('should
|
|
46
|
-
expect(mediaControl
|
|
47
|
-
expect(mediaControl.
|
|
48
|
+
it('should hide duration and position indicators', () => {
|
|
49
|
+
expect(mediaControl.toggleElement).toHaveBeenCalledWith('duration', false)
|
|
50
|
+
expect(mediaControl.toggleElement).toHaveBeenCalledWith('position', false)
|
|
48
51
|
})
|
|
49
|
-
it('should
|
|
50
|
-
expect(mediaControl
|
|
52
|
+
it('should render to the media control', () => {
|
|
53
|
+
expect(mediaControl.putElement).toHaveBeenCalledWith('dvr', dvrControls.el)
|
|
51
54
|
})
|
|
52
|
-
if (indicateDvr) {
|
|
53
|
-
it('should indicate DVR mode', () => {
|
|
54
|
-
expect(mediaControl.$el.hasClass('dvr')).toBe(true)
|
|
55
|
-
})
|
|
56
|
-
} else {
|
|
57
|
-
it('should not indicate DVR mode', () => {
|
|
58
|
-
expect(mediaControl.$el.hasClass('dvr')).toBe(false)
|
|
59
|
-
})
|
|
60
|
-
}
|
|
61
55
|
})
|
|
62
56
|
describe('when back_to_live button is clicked', () => {
|
|
63
57
|
beforeEach(() => {
|
|
@@ -76,16 +70,20 @@ describe('DvrControls', () => {
|
|
|
76
70
|
})
|
|
77
71
|
})
|
|
78
72
|
})
|
|
79
|
-
describe('
|
|
73
|
+
describe('basically', () => {
|
|
80
74
|
beforeEach(() => {
|
|
81
|
-
core.getPlaybackType.mockReturnValue(
|
|
75
|
+
core.getPlaybackType.mockReturnValue(Playback.VOD)
|
|
76
|
+
core.activeContainer.getPlaybackType.mockReturnValue(Playback.VOD)
|
|
77
|
+
core.activePlayback.getPlaybackType.mockReturnValue(Playback.VOD)
|
|
82
78
|
})
|
|
83
79
|
beforeEach(() => {
|
|
84
|
-
core.trigger(
|
|
85
|
-
core.trigger(
|
|
80
|
+
core.trigger(Events.CORE_READY)
|
|
81
|
+
core.trigger(Events.CORE_ACTIVE_CONTAINER_CHANGED, core.activeContainer)
|
|
86
82
|
})
|
|
87
|
-
it('should
|
|
88
|
-
expect(dvrControls.el.
|
|
83
|
+
it('should render', () => {
|
|
84
|
+
expect(dvrControls.el.innerHTML).toMatchSnapshot()
|
|
85
|
+
expect(dvrControls.el.textContent).toContain('live')
|
|
86
|
+
expect(dvrControls.el.textContent).toContain('back_to_live')
|
|
89
87
|
})
|
|
90
88
|
})
|
|
91
89
|
})
|
|
@@ -1,43 +1,19 @@
|
|
|
1
1
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
2
|
|
|
3
|
-
exports[`DvrControls >
|
|
4
|
-
"<div class="live-info">live</div>
|
|
5
|
-
<button type="button" class="live-button" aria-label="back_to_live">back_to_live</button>
|
|
3
|
+
exports[`DvrControls > basically > should render 1`] = `
|
|
4
|
+
"<div class="live-info" id="media-control-live">live</div>
|
|
5
|
+
<button type="button" class="live-button" aria-label="back_to_live" id="media-control-back-to-live">back_to_live</button>
|
|
6
6
|
"
|
|
7
7
|
`;
|
|
8
8
|
|
|
9
|
-
exports[`DvrControls > live stream > DVR at live edge > should render
|
|
10
|
-
"<div class="
|
|
11
|
-
<button type="button" class="live-button" aria-label="back_to_live">back_to_live</button>
|
|
12
|
-
</div></div>
|
|
13
|
-
<div class="media-control-right-panel" data-media-control=""></div>
|
|
14
|
-
<div class="media-control-center-panel" data-media-control=""></div>"
|
|
15
|
-
`;
|
|
16
|
-
|
|
17
|
-
exports[`DvrControls > live stream > DVR behind live edge > should render 1`] = `
|
|
18
|
-
"<div class="live-info">live</div>
|
|
19
|
-
<button type="button" class="live-button" aria-label="back_to_live">back_to_live</button>
|
|
9
|
+
exports[`DvrControls > live stream > DVR at live edge > should render 1`] = `
|
|
10
|
+
"<div class="live-info" id="media-control-live">live</div>
|
|
11
|
+
<button type="button" class="live-button" aria-label="back_to_live" id="media-control-back-to-live">back_to_live</button>
|
|
20
12
|
"
|
|
21
13
|
`;
|
|
22
14
|
|
|
23
|
-
exports[`DvrControls > live stream > DVR behind live edge > should render to the media control left panel 1`] = `
|
|
24
|
-
"<div class="media-control-left-panel" data-media-control=""><div class="dvr-controls" data-dvr-controls=""><div class="live-info">live</div>
|
|
25
|
-
<button type="button" class="live-button" aria-label="back_to_live">back_to_live</button>
|
|
26
|
-
</div></div>
|
|
27
|
-
<div class="media-control-right-panel" data-media-control=""></div>
|
|
28
|
-
<div class="media-control-center-panel" data-media-control=""></div>"
|
|
29
|
-
`;
|
|
30
|
-
|
|
31
15
|
exports[`DvrControls > live stream > no DVR > should render 1`] = `
|
|
32
|
-
"<div class="live-info">live</div>
|
|
33
|
-
<button type="button" class="live-button" aria-label="back_to_live">back_to_live</button>
|
|
16
|
+
"<div class="live-info" id="media-control-live">live</div>
|
|
17
|
+
<button type="button" class="live-button" aria-label="back_to_live" id="media-control-back-to-live">back_to_live</button>
|
|
34
18
|
"
|
|
35
19
|
`;
|
|
36
|
-
|
|
37
|
-
exports[`DvrControls > live stream > no DVR > should render to the media control left panel 1`] = `
|
|
38
|
-
"<div class="media-control-left-panel" data-media-control=""><div class="dvr-controls" data-dvr-controls=""><div class="live-info">live</div>
|
|
39
|
-
<button type="button" class="live-button" aria-label="back_to_live">back_to_live</button>
|
|
40
|
-
</div></div>
|
|
41
|
-
<div class="media-control-right-panel" data-media-control=""></div>
|
|
42
|
-
<div class="media-control-center-panel" data-media-control=""></div>"
|
|
43
|
-
`;
|