@gcorevideo/player 2.25.6 → 2.25.8
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/audio-tracks/template.ejs +5 -4
- package/assets/bottom-gear/gear-sub-menu.scss +4 -9
- package/assets/bottom-gear/gear.scss +1 -2
- package/assets/media-control/container.scss +0 -13
- package/assets/media-control/media-control.scss +110 -8
- package/assets/media-control/width270.scss +3 -9
- package/assets/media-control/width370.scss +6 -40
- package/assets/multi-camera/style.scss +0 -5
- package/assets/picture-in-picture/style.scss +1 -2
- package/assets/subtitles/combobox.ejs +27 -6
- package/assets/subtitles/string.ejs +1 -1
- package/assets/subtitles/style.scss +16 -69
- package/dist/core.js +1 -1
- package/dist/index.css +1019 -1117
- package/dist/index.embed.js +180 -123
- package/dist/index.js +161 -107
- package/lib/plugins/audio-selector/AudioTracks.d.ts +4 -3
- package/lib/plugins/audio-selector/AudioTracks.d.ts.map +1 -1
- package/lib/plugins/audio-selector/AudioTracks.js +41 -23
- package/lib/plugins/bottom-gear/BottomGear.d.ts +1 -1
- package/lib/plugins/bottom-gear/BottomGear.d.ts.map +1 -1
- package/lib/plugins/bottom-gear/BottomGear.js +3 -4
- package/lib/plugins/media-control/MediaControl.d.ts +4 -0
- package/lib/plugins/media-control/MediaControl.d.ts.map +1 -1
- package/lib/plugins/media-control/MediaControl.js +8 -1
- package/lib/plugins/subtitles/ClosedCaptions.d.ts +7 -4
- package/lib/plugins/subtitles/ClosedCaptions.d.ts.map +1 -1
- package/lib/plugins/subtitles/ClosedCaptions.js +64 -34
- package/lib/testUtils.d.ts.map +1 -1
- package/lib/testUtils.js +2 -0
- package/package.json +1 -1
- package/src/plugins/audio-selector/AudioTracks.ts +53 -29
- package/src/plugins/audio-selector/__tests__/AudioTracks.test.ts +60 -45
- package/src/plugins/audio-selector/__tests__/__snapshots__/AudioSelector.test.ts.snap +24 -24
- package/src/plugins/audio-selector/__tests__/__snapshots__/AudioTracks.test.ts.snap +21 -18
- package/src/plugins/bottom-gear/BottomGear.ts +3 -4
- package/src/plugins/bottom-gear/__tests__/BottomGear.test.ts +1 -1
- package/src/plugins/media-control/MediaControl.ts +11 -1
- package/src/plugins/media-control/__tests__/__snapshots__/MediaControl.test.ts.snap +6 -6
- package/src/plugins/subtitles/ClosedCaptions.ts +66 -35
- package/src/plugins/subtitles/__tests__/ClosedCaptions.test.ts +220 -35
- package/src/plugins/subtitles/__tests__/__snapshots__/ClosedCaptions.test.ts.snap +8 -19
- package/src/testUtils.ts +2 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/assets/audio-tracks/style.scss +0 -111
|
@@ -49,6 +49,8 @@ const STANDARD_MEDIA_CONTROL_ELEMENTS: string[] = [
|
|
|
49
49
|
'volume',
|
|
50
50
|
]
|
|
51
51
|
|
|
52
|
+
const MENU_VMARGIN = 12
|
|
53
|
+
|
|
52
54
|
/**
|
|
53
55
|
* Built-in media control elements.
|
|
54
56
|
* @beta
|
|
@@ -562,6 +564,13 @@ export class MediaControl extends UICorePlugin {
|
|
|
562
564
|
)
|
|
563
565
|
}
|
|
564
566
|
|
|
567
|
+
/**
|
|
568
|
+
* @returns Vertical space available to render a popup menu
|
|
569
|
+
*/
|
|
570
|
+
getAvailablePopupHeight() {
|
|
571
|
+
return this.getAvailableHeight() - MENU_VMARGIN * 2
|
|
572
|
+
}
|
|
573
|
+
|
|
565
574
|
/**
|
|
566
575
|
* Set the initial volume, which is preserved when playback is interrupted by an advertisement
|
|
567
576
|
*/
|
|
@@ -681,6 +690,7 @@ export class MediaControl extends UICorePlugin {
|
|
|
681
690
|
const pos = offset
|
|
682
691
|
? Math.min(1, Math.max(offset / this.$seekBarContainer.width(), 0))
|
|
683
692
|
: 0
|
|
693
|
+
|
|
684
694
|
if (this.settings.seekEnabled) {
|
|
685
695
|
// TODO test that it works when the element does not exist
|
|
686
696
|
this.$seekBarHover.css({ left: hoverOffset })
|
|
@@ -1214,7 +1224,7 @@ export class MediaControl extends UICorePlugin {
|
|
|
1214
1224
|
const panel = this.getElementLocation(name)
|
|
1215
1225
|
if (panel) {
|
|
1216
1226
|
element.attr(`data-${name}`, '')
|
|
1217
|
-
element.addClass('
|
|
1227
|
+
element.addClass('media-control-item')
|
|
1218
1228
|
mountTo(panel, element)
|
|
1219
1229
|
}
|
|
1220
1230
|
}
|
|
@@ -472,7 +472,7 @@ exports[`MediaControl > slot > audiotracks > should put the element according to
|
|
|
472
472
|
|
|
473
473
|
<div class="media-control-right-panel" data-media-control="">
|
|
474
474
|
|
|
475
|
-
<div class="my-media-control
|
|
475
|
+
<div class="my-media-control media-control-item" id="my-media-control" data-audiotracks="">test</div></div>
|
|
476
476
|
|
|
477
477
|
</div>
|
|
478
478
|
<style>:root {}</style>"
|
|
@@ -521,7 +521,7 @@ exports[`MediaControl > slot > cc > should put the element according to layout 1
|
|
|
521
521
|
|
|
522
522
|
<div class="media-control-right-panel" data-media-control="">
|
|
523
523
|
|
|
524
|
-
<div class="my-media-control
|
|
524
|
+
<div class="my-media-control media-control-item" id="my-media-control" data-cc="">test</div></div>
|
|
525
525
|
|
|
526
526
|
</div>
|
|
527
527
|
<style>:root {}</style>"
|
|
@@ -564,7 +564,7 @@ exports[`MediaControl > slot > clips > should put the element according to layou
|
|
|
564
564
|
|
|
565
565
|
<div class="media-control-indicator gcore-skin-text-color" data-clips=""></div>
|
|
566
566
|
|
|
567
|
-
<div class="my-media-control
|
|
567
|
+
<div class="my-media-control media-control-item" id="my-media-control" data-clips="">test</div></div>
|
|
568
568
|
|
|
569
569
|
|
|
570
570
|
|
|
@@ -613,7 +613,7 @@ exports[`MediaControl > slot > dvr > should put the element according to layout
|
|
|
613
613
|
|
|
614
614
|
<div class="media-control-indicator gcore-skin-text-color" data-clips=""></div>
|
|
615
615
|
|
|
616
|
-
<div class="my-media-control
|
|
616
|
+
<div class="my-media-control media-control-item" id="my-media-control" data-dvr="">test</div></div>
|
|
617
617
|
|
|
618
618
|
|
|
619
619
|
|
|
@@ -668,7 +668,7 @@ exports[`MediaControl > slot > gear > should put the element according to layout
|
|
|
668
668
|
|
|
669
669
|
<div class="media-control-right-panel" data-media-control="">
|
|
670
670
|
|
|
671
|
-
<div class="my-media-control
|
|
671
|
+
<div class="my-media-control media-control-item" id="my-media-control" data-gear="">test</div></div>
|
|
672
672
|
|
|
673
673
|
</div>
|
|
674
674
|
<style>:root {}</style>"
|
|
@@ -717,7 +717,7 @@ exports[`MediaControl > slot > pip > should put the element according to layout
|
|
|
717
717
|
|
|
718
718
|
<div class="media-control-right-panel" data-media-control="">
|
|
719
719
|
|
|
720
|
-
<div class="my-media-control
|
|
720
|
+
<div class="my-media-control media-control-item" id="my-media-control" data-pip="">test</div></div>
|
|
721
721
|
|
|
722
722
|
</div>
|
|
723
723
|
<style>:root {}</style>"
|
|
@@ -64,6 +64,8 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
64
64
|
|
|
65
65
|
private active = false
|
|
66
66
|
|
|
67
|
+
private open = false
|
|
68
|
+
|
|
67
69
|
private track: TextTrackItem | null = null
|
|
68
70
|
|
|
69
71
|
private tracks: TextTrackItem[] = []
|
|
@@ -91,16 +93,16 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
91
93
|
return VERSION
|
|
92
94
|
}
|
|
93
95
|
|
|
94
|
-
private static readonly
|
|
96
|
+
private static readonly templateControl = template(comboboxHTML)
|
|
95
97
|
|
|
96
|
-
private static readonly
|
|
98
|
+
private static readonly templateLine = template(stringHTML)
|
|
97
99
|
|
|
98
100
|
/**
|
|
99
101
|
* @internal
|
|
100
102
|
*/
|
|
101
103
|
override get attributes() {
|
|
102
104
|
return {
|
|
103
|
-
class: 'media-control-cc',
|
|
105
|
+
class: 'media-control-cc media-control-dd__wrap',
|
|
104
106
|
}
|
|
105
107
|
}
|
|
106
108
|
|
|
@@ -109,8 +111,8 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
109
111
|
*/
|
|
110
112
|
override get events() {
|
|
111
113
|
return {
|
|
112
|
-
'click #cc-
|
|
113
|
-
'click #cc-button': 'toggleMenu',
|
|
114
|
+
'click #gplayer-cc-menu [data-item]': 'onItemSelect',
|
|
115
|
+
'click #gplayer-cc-button': 'toggleMenu',
|
|
114
116
|
}
|
|
115
117
|
}
|
|
116
118
|
|
|
@@ -136,10 +138,9 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
136
138
|
}
|
|
137
139
|
|
|
138
140
|
private onCoreReady() {
|
|
139
|
-
trace(`${T} onCoreReady`)
|
|
140
141
|
const mediaControl = this.core.getPlugin('media_control')
|
|
141
142
|
assert(mediaControl, 'media_control plugin is required')
|
|
142
|
-
this.listenTo(mediaControl, Events.MEDIACONTROL_RENDERED, this.
|
|
143
|
+
this.listenTo(mediaControl, Events.MEDIACONTROL_RENDERED, this.mount)
|
|
143
144
|
this.listenTo(mediaControl, Events.MEDIACONTROL_HIDE, () => {
|
|
144
145
|
this.hideMenu()
|
|
145
146
|
})
|
|
@@ -155,7 +156,6 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
155
156
|
}
|
|
156
157
|
|
|
157
158
|
private onContainerChanged() {
|
|
158
|
-
trace(`${T} onContainerChanged`)
|
|
159
159
|
this.listenTo(
|
|
160
160
|
this.core.activeContainer,
|
|
161
161
|
Events.CONTAINER_FULLSCREEN,
|
|
@@ -176,6 +176,10 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
176
176
|
Events.PLAYBACK_SUBTITLE_CHANGED,
|
|
177
177
|
this.onSubtitleChanged,
|
|
178
178
|
)
|
|
179
|
+
this.listenTo(this.core.activeContainer, Events.CONTAINER_CLICK, () => {
|
|
180
|
+
// TODO test
|
|
181
|
+
this.hideMenu()
|
|
182
|
+
})
|
|
179
183
|
|
|
180
184
|
// fix for iOS
|
|
181
185
|
const video = this.core.activePlayback.el
|
|
@@ -197,6 +201,7 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
197
201
|
private onSubtitleAvailable() {
|
|
198
202
|
trace(`${T} onSubtitleAvailable`)
|
|
199
203
|
this.applyTracks()
|
|
204
|
+
this.mount()
|
|
200
205
|
}
|
|
201
206
|
|
|
202
207
|
private onSubtitleChanged({ id }: { id: number }) {
|
|
@@ -276,6 +281,7 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
276
281
|
|
|
277
282
|
try {
|
|
278
283
|
this.resizeFont()
|
|
284
|
+
this.clampPopup()
|
|
279
285
|
} catch (error) {
|
|
280
286
|
reportError(error)
|
|
281
287
|
}
|
|
@@ -286,7 +292,10 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
286
292
|
*/
|
|
287
293
|
hide() {
|
|
288
294
|
this.active = false
|
|
295
|
+
this.open = false
|
|
289
296
|
this.renderIcon()
|
|
297
|
+
this.$el.find('#gplayer-cc-menu').hide()
|
|
298
|
+
this.$el.find('#gplayer-cc-button').attr('aria-expanded', 'false')
|
|
290
299
|
this.$line.hide()
|
|
291
300
|
if (this.tracks) {
|
|
292
301
|
for (const t of this.tracks) {
|
|
@@ -337,20 +346,21 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
337
346
|
return this
|
|
338
347
|
}
|
|
339
348
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
this.$el.find('#cc-
|
|
348
|
-
this.
|
|
349
|
-
this.$line
|
|
349
|
+
this.$el.html(
|
|
350
|
+
ClosedCaptions.templateControl({
|
|
351
|
+
tracks: this.tracks ?? [],
|
|
352
|
+
i18n: this.core.i18n,
|
|
353
|
+
current: this.track?.id ?? -1,
|
|
354
|
+
}),
|
|
355
|
+
)
|
|
356
|
+
this.$el.find('#gplayer-cc-menu').hide()
|
|
357
|
+
this.open = false
|
|
358
|
+
this.core.activeContainer.$el.find('#gplayer-cc-line').remove()
|
|
359
|
+
this.$line = $(ClosedCaptions.templateLine())
|
|
350
360
|
this.resizeFont()
|
|
361
|
+
this.clampPopup()
|
|
351
362
|
|
|
352
363
|
this.core.activeContainer.$el.append(this.$line)
|
|
353
|
-
mediaControl.slot('cc', this.$el)
|
|
354
364
|
|
|
355
365
|
this.updateSelection()
|
|
356
366
|
|
|
@@ -371,11 +381,12 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
371
381
|
}
|
|
372
382
|
|
|
373
383
|
private onItemSelect(event: MouseEvent) {
|
|
374
|
-
|
|
384
|
+
// event.target does not exist for some reason in tests
|
|
385
|
+
const id =
|
|
386
|
+
((event.target ?? event.currentTarget) as HTMLElement).dataset?.item ??
|
|
387
|
+
'-1'
|
|
375
388
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
localStorage.setItem(LOCAL_STORAGE_CC_ID, id)
|
|
389
|
+
localStorage.setItem(LOCAL_STORAGE_CC_ID, id) // TODO store language instead
|
|
379
390
|
this.selectItem(this.findById(Number(id)))
|
|
380
391
|
this.hideMenu()
|
|
381
392
|
return false
|
|
@@ -398,31 +409,37 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
398
409
|
}
|
|
399
410
|
|
|
400
411
|
private hideMenu() {
|
|
401
|
-
|
|
402
|
-
this.$el.find('#cc-
|
|
412
|
+
this.open = false
|
|
413
|
+
this.$el.find('#gplayer-cc-menu').hide()
|
|
414
|
+
this.$el.find('#gplayer-cc-button').attr('aria-expanded', 'false')
|
|
403
415
|
}
|
|
404
416
|
|
|
405
417
|
private toggleMenu() {
|
|
406
|
-
trace(`${T} toggleMenu`, {display: this.$el.find('#cc-select').css('display')})
|
|
407
418
|
this.core
|
|
408
419
|
.getPlugin('media_control')
|
|
409
420
|
.trigger(ExtendedEvents.MEDIACONTROL_MENU_COLLAPSE, this.name)
|
|
410
|
-
this
|
|
411
|
-
|
|
421
|
+
this.open = !this.open
|
|
422
|
+
if (this.open) {
|
|
423
|
+
this.$el.find('#gplayer-cc-menu').show()
|
|
424
|
+
} else {
|
|
425
|
+
this.$el.find('#gplayer-cc-menu').hide()
|
|
426
|
+
}
|
|
427
|
+
this.$el.find('#gplayer-cc-button').attr('aria-expanded', this.open)
|
|
412
428
|
}
|
|
413
429
|
|
|
414
430
|
private itemElement(id: number): ZeptoResult {
|
|
415
|
-
|
|
431
|
+
// TODO fix semantically
|
|
432
|
+
return this.$el.find(`#gplayer-cc-menu [data-item="${id}"]`).parent()
|
|
416
433
|
}
|
|
417
434
|
|
|
418
435
|
private allItemElements(): ZeptoResult {
|
|
419
|
-
return this.$('#cc-
|
|
436
|
+
return this.$el.find('#gplayer-cc-menu li') // TODO fix semantically
|
|
420
437
|
}
|
|
421
438
|
|
|
422
439
|
private selectSubtitles() {
|
|
423
440
|
const trackId = this.track ? this.track.id : -1
|
|
424
441
|
|
|
425
|
-
this.core.activePlayback.closedCaptionsTrackId = trackId
|
|
442
|
+
this.core.activePlayback.closedCaptionsTrackId = trackId // TODO test
|
|
426
443
|
}
|
|
427
444
|
|
|
428
445
|
private getSubtitleText(track: TextTrack) {
|
|
@@ -434,6 +451,7 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
434
451
|
for (const cue of cues) {
|
|
435
452
|
if (currentTime >= cue.startTime && currentTime <= cue.endTime) {
|
|
436
453
|
lines.push((cue as VTTCue).getCueAsHTML().textContent)
|
|
454
|
+
// TODO break?
|
|
437
455
|
}
|
|
438
456
|
}
|
|
439
457
|
}
|
|
@@ -464,10 +482,8 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
464
482
|
.removeClass('current')
|
|
465
483
|
.find('a')
|
|
466
484
|
.removeClass('gcore-skin-active')
|
|
485
|
+
.attr('aria-checked', 'false')
|
|
467
486
|
|
|
468
|
-
trace(`${T} highlightCurrentSubtitles`, {
|
|
469
|
-
track: this.track?.id,
|
|
470
|
-
})
|
|
471
487
|
const currentLevelElement = this.itemElement(
|
|
472
488
|
this.track ? this.track.id : -1,
|
|
473
489
|
)
|
|
@@ -475,11 +491,26 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
475
491
|
.addClass('current')
|
|
476
492
|
.find('a')
|
|
477
493
|
.addClass('gcore-skin-active')
|
|
494
|
+
.attr('aria-checked', 'true')
|
|
478
495
|
}
|
|
479
496
|
|
|
480
497
|
private renderIcon() {
|
|
498
|
+
// render both icons at once
|
|
481
499
|
const icon = this.active ? subtitlesOnIcon : subtitlesOffIcon
|
|
500
|
+
this.$el.find('#gplayer-cc-button').html(icon)
|
|
501
|
+
}
|
|
482
502
|
|
|
483
|
-
|
|
503
|
+
private clampPopup() {
|
|
504
|
+
const availableHeight = this.core
|
|
505
|
+
.getPlugin('media_control')
|
|
506
|
+
.getAvailablePopupHeight()
|
|
507
|
+
this.$el.find('#gplayer-cc-menu').css('max-height', `${availableHeight}px`)
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
private mount() {
|
|
511
|
+
if (this.shouldRender()) {
|
|
512
|
+
const mediaControl = this.core.getPlugin('media_control')
|
|
513
|
+
mediaControl.slot('cc', this.$el)
|
|
514
|
+
}
|
|
484
515
|
}
|
|
485
516
|
}
|
|
@@ -4,9 +4,9 @@ import { ClosedCaptions } from '../ClosedCaptions.js'
|
|
|
4
4
|
import { createMockCore, createMockMediaControl } from '../../../testUtils.js'
|
|
5
5
|
import { ExtendedEvents } from '../../media-control/MediaControl.js'
|
|
6
6
|
|
|
7
|
-
import { LogTracer, Logger, setTracer } from '@gcorevideo/utils'
|
|
8
7
|
import { Events } from '@clappr/core'
|
|
9
|
-
|
|
8
|
+
|
|
9
|
+
// import { LogTracer, Logger, setTracer } from '@gcorevideo/utils'
|
|
10
10
|
|
|
11
11
|
// Logger.enable('*')
|
|
12
12
|
// setTracer(new LogTracer('ClosedCaptions.test'))
|
|
@@ -18,6 +18,7 @@ describe('ClosedCaptions', () => {
|
|
|
18
18
|
beforeEach(() => {
|
|
19
19
|
core = createMockCore()
|
|
20
20
|
mediaControl = createMockMediaControl(core)
|
|
21
|
+
mediaControl.getAvailablePopupHeight = vi.fn().mockReturnValue(211)
|
|
21
22
|
core.getPlugin = vi.fn().mockImplementation((name) => {
|
|
22
23
|
if (name === 'media_control') {
|
|
23
24
|
return mediaControl
|
|
@@ -31,44 +32,60 @@ describe('ClosedCaptions', () => {
|
|
|
31
32
|
core.emit(Events.CORE_READY)
|
|
32
33
|
core.activePlayback.el = document.createElement('video')
|
|
33
34
|
core.emit(Events.CORE_ACTIVE_CONTAINER_CHANGED, core.activeContainer)
|
|
34
|
-
core.activePlayback.closedCaptionsTracks = [
|
|
35
|
-
{
|
|
36
|
-
id: 1,
|
|
37
|
-
name: 'English',
|
|
38
|
-
track: {
|
|
39
|
-
language: 'en',
|
|
40
|
-
kind: 'subtitles',
|
|
41
|
-
label: 'English',
|
|
42
|
-
mode: 'hidden',
|
|
43
|
-
cues: [],
|
|
44
|
-
},
|
|
45
|
-
},
|
|
46
|
-
{
|
|
47
|
-
id: 2,
|
|
48
|
-
name: 'Spanish',
|
|
49
|
-
track: {
|
|
50
|
-
language: 'es',
|
|
51
|
-
kind: 'subtitles',
|
|
52
|
-
label: 'Spanish',
|
|
53
|
-
mode: 'hidden',
|
|
54
|
-
cues: [],
|
|
55
|
-
},
|
|
56
|
-
},
|
|
57
|
-
]
|
|
58
|
-
core.activePlayback.emit(Events.PLAYBACK_SUBTITLE_AVAILABLE)
|
|
59
|
-
core.activeContainer.emit(Events.CONTAINER_SUBTITLE_AVAILABLE)
|
|
60
35
|
})
|
|
61
36
|
it('should render', () => {
|
|
62
37
|
expect(cc.el.innerHTML).toMatchSnapshot()
|
|
63
|
-
expect(cc.$el.find('#cc-button').length).toEqual(1)
|
|
64
|
-
expect(
|
|
38
|
+
expect(cc.$el.find('#gplayer-cc-button').length).toEqual(1)
|
|
39
|
+
expect(cc.$el.find('#gplayer-cc-menu').css('display')).toEqual('none')
|
|
40
|
+
expect(core.activeContainer.$el.find('#gplayer-cc-line').length).toEqual(
|
|
41
|
+
1,
|
|
42
|
+
)
|
|
43
|
+
})
|
|
44
|
+
it('should clamp popup to availableheight', () => {
|
|
45
|
+
expect(cc.$el.find('#gplayer-cc-menu').css('max-height')).toBe('211px')
|
|
46
|
+
})
|
|
47
|
+
describe('until subtitle tracks are available', () => {
|
|
48
|
+
it('should not mount', () => {
|
|
49
|
+
expect(mediaControl.slot).not.toHaveBeenCalledWith(
|
|
50
|
+
'cc',
|
|
51
|
+
expect.anything(),
|
|
52
|
+
)
|
|
53
|
+
emitSubtitleAvailable(core)
|
|
54
|
+
expect(mediaControl.slot).toHaveBeenCalledWith('cc', cc.$el)
|
|
55
|
+
})
|
|
56
|
+
})
|
|
57
|
+
describe('when viewport is resized', () => {
|
|
58
|
+
beforeEach(() => {
|
|
59
|
+
mediaControl.getAvailablePopupHeight = vi.fn().mockReturnValue(197)
|
|
60
|
+
core.activeContainer.emit(Events.CONTAINER_RESIZE, {
|
|
61
|
+
width: 320,
|
|
62
|
+
height: 260,
|
|
63
|
+
})
|
|
64
|
+
core.emit(Events.CORE_RESIZE, { width: 320, height: 260 })
|
|
65
|
+
})
|
|
66
|
+
it('should clamp popup height', () => {
|
|
67
|
+
expect(cc.$el.find('#gplayer-cc-menu').css('max-height')).toBe('197px')
|
|
68
|
+
})
|
|
69
|
+
})
|
|
70
|
+
describe('when media control is rerendered', () => {
|
|
71
|
+
beforeEach(() => {
|
|
72
|
+
emitSubtitleAvailable(core)
|
|
73
|
+
mediaControl.trigger(Events.MEDIACONTROL_RENDERED)
|
|
74
|
+
})
|
|
75
|
+
it('should mount', () => {
|
|
76
|
+
expect(mediaControl.slot).toHaveBeenCalledWith('cc', cc.$el)
|
|
77
|
+
})
|
|
65
78
|
})
|
|
66
79
|
describe('when button is clicked', () => {
|
|
67
80
|
beforeEach(() => {
|
|
68
|
-
|
|
81
|
+
emitSubtitleAvailable(core)
|
|
82
|
+
cc.$el.find('#gplayer-cc-button').click()
|
|
69
83
|
})
|
|
70
84
|
it('should open menu', () => {
|
|
71
|
-
expect(cc.$el.find('#cc-
|
|
85
|
+
expect(cc.$el.find('#gplayer-cc-menu').css('display')).not.toBe('none')
|
|
86
|
+
expect(cc.$el.find('#gplayer-cc-button').attr('aria-expanded')).toBe(
|
|
87
|
+
'true',
|
|
88
|
+
)
|
|
72
89
|
})
|
|
73
90
|
it('should collapse all other menus', () => {
|
|
74
91
|
expect(mediaControl.trigger).toHaveBeenCalledWith(
|
|
@@ -79,20 +96,188 @@ describe('ClosedCaptions', () => {
|
|
|
79
96
|
})
|
|
80
97
|
describe('when clicked twice', () => {
|
|
81
98
|
beforeEach(() => {
|
|
82
|
-
|
|
99
|
+
emitSubtitleAvailable(core)
|
|
100
|
+
cc.$el.find('#gplayer-cc-button').click().click()
|
|
83
101
|
})
|
|
84
102
|
it('should collapse the menu', () => {
|
|
85
|
-
expect(cc.$el.find('#cc-
|
|
103
|
+
expect(cc.$el.find('#gplayer-cc-menu').css('display')).toBe('none')
|
|
104
|
+
expect(cc.$el.find('#gplayer-cc-button').attr('aria-expanded')).toBe(
|
|
105
|
+
'false',
|
|
106
|
+
)
|
|
86
107
|
})
|
|
87
108
|
})
|
|
88
109
|
describe('when media control is hidden', () => {
|
|
89
110
|
beforeEach(() => {
|
|
111
|
+
emitSubtitleAvailable(core)
|
|
90
112
|
cc.$el.find('#cc-button').click()
|
|
91
113
|
mediaControl.trigger(Events.MEDIACONTROL_HIDE)
|
|
92
114
|
})
|
|
93
115
|
it('should hide menu', () => {
|
|
94
|
-
expect(cc.$el.find('#cc-
|
|
116
|
+
expect(cc.$el.find('#gplayer-cc-menu').css('display')).toBe('none')
|
|
117
|
+
})
|
|
118
|
+
})
|
|
119
|
+
describe('when container is clicked', () => {
|
|
120
|
+
beforeEach(() => {
|
|
121
|
+
emitSubtitleAvailable(core)
|
|
122
|
+
cc.$el.find('#gplayer-cc-button').click()
|
|
123
|
+
core.activeContainer.emit(Events.CONTAINER_CLICK)
|
|
124
|
+
})
|
|
125
|
+
it('should hide menu', () => {
|
|
126
|
+
expect(cc.$el.find('#gplayer-cc-menu').css('display')).toBe('none')
|
|
127
|
+
expect(cc.$el.find('#gplayer-cc-button').attr('aria-expanded')).toBe(
|
|
128
|
+
'false',
|
|
129
|
+
)
|
|
130
|
+
})
|
|
131
|
+
})
|
|
132
|
+
describe('when subtitle is changed', () => {
|
|
133
|
+
beforeEach(async () => {
|
|
134
|
+
emitSubtitleAvailable(core)
|
|
135
|
+
await new Promise((resolve) => setTimeout(resolve, 100))
|
|
136
|
+
core.activePlayback.getCurrentTime = vi.fn().mockReturnValue(7)
|
|
137
|
+
core.activeContainer.getCurrentTime = vi.fn().mockReturnValue(7)
|
|
138
|
+
core.activePlayback.closedCaptionsTracks[1].track.cues = [
|
|
139
|
+
{
|
|
140
|
+
startTime: 0,
|
|
141
|
+
endTime: 5,
|
|
142
|
+
text: 'Alright this is me',
|
|
143
|
+
getCueAsHTML: vi
|
|
144
|
+
.fn()
|
|
145
|
+
.mockImplementation(() =>
|
|
146
|
+
document.createTextNode('Alright this is me'),
|
|
147
|
+
),
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
startTime: 5,
|
|
151
|
+
endTime: 10,
|
|
152
|
+
text: 'Welcome to my channel',
|
|
153
|
+
getCueAsHTML: vi
|
|
154
|
+
.fn()
|
|
155
|
+
.mockImplementation(() =>
|
|
156
|
+
document.createTextNode('Welcome to my channel'),
|
|
157
|
+
),
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
startTime: 10,
|
|
161
|
+
endTime: 15,
|
|
162
|
+
text: 'Thank you for watching',
|
|
163
|
+
getCueAsHTML: vi
|
|
164
|
+
.fn()
|
|
165
|
+
.mockImplementation(() =>
|
|
166
|
+
document.createTextNode('Thank you for watching'),
|
|
167
|
+
),
|
|
168
|
+
},
|
|
169
|
+
]
|
|
170
|
+
core.activePlayback.emit(Events.PLAYBACK_SUBTITLE_CHANGED, { id: 2 })
|
|
171
|
+
})
|
|
172
|
+
it('should activate subtitle track', () => {
|
|
173
|
+
expect(core.activePlayback.closedCaptionsTracks[1].track.mode).toBe(
|
|
174
|
+
'showing',
|
|
175
|
+
)
|
|
176
|
+
expect(core.activePlayback.closedCaptionsTracks[0].track.mode).toBe(
|
|
177
|
+
'hidden',
|
|
178
|
+
)
|
|
179
|
+
})
|
|
180
|
+
it('should show active subtitle text', () => {
|
|
181
|
+
expect(
|
|
182
|
+
core.activeContainer.$el.find('#gplayer-cc-line').text().trim(),
|
|
183
|
+
).toEqual('Welcome to my channel')
|
|
184
|
+
})
|
|
185
|
+
})
|
|
186
|
+
describe('when subtitle is selected from menu', () => {
|
|
187
|
+
beforeEach(() => {
|
|
188
|
+
emitSubtitleAvailable(core)
|
|
189
|
+
cc.$el.find('#gplayer-cc-menu li:nth-child(2) a').click()
|
|
190
|
+
})
|
|
191
|
+
it('should activate subtitle track', () => {
|
|
192
|
+
expect(core.activePlayback.closedCaptionsTrackId).toEqual(2)
|
|
193
|
+
})
|
|
194
|
+
it('should highlight selected menu item', () => {
|
|
195
|
+
expect(
|
|
196
|
+
cc.$el.find('#gplayer-cc-menu li:nth-child(2)').hasClass('current'),
|
|
197
|
+
).toBe(true)
|
|
198
|
+
expect(
|
|
199
|
+
cc.$el
|
|
200
|
+
.find('#gplayer-cc-menu li:nth-child(2) a')
|
|
201
|
+
.attr('aria-checked'),
|
|
202
|
+
).toBe('true')
|
|
203
|
+
expect(cc.$el.find('#gplayer-cc-menu li.current').length).toBe(1)
|
|
204
|
+
expect(
|
|
205
|
+
cc.$el.find('#gplayer-cc-menu li a[aria-checked="true"]').length,
|
|
206
|
+
).toBe(1)
|
|
207
|
+
})
|
|
208
|
+
it('should collapse menu', () => {
|
|
209
|
+
expect(cc.$el.find('#gplayer-cc-menu').css('display')).toBe('none')
|
|
210
|
+
})
|
|
211
|
+
})
|
|
212
|
+
describe('when user turns off subtitles', () => {
|
|
213
|
+
beforeEach(() => {
|
|
214
|
+
emitSubtitleAvailable(core)
|
|
215
|
+
core.activePlayback.closedCaptionsTracks[1].track.mode = 'showing'
|
|
216
|
+
core.activePlayback.closedCaptionsTrackId = 2
|
|
217
|
+
core.activePlayback.emit(Events.PLAYBACK_SUBTITLE_CHANGED, { id: 2 })
|
|
218
|
+
cc.$el.find('#gplayer-cc-button').click()
|
|
219
|
+
cc.$el.find('#gplayer-cc-menu li:nth-child(3) a').click() // off
|
|
220
|
+
})
|
|
221
|
+
it('should hide menu', () => {
|
|
222
|
+
expect(cc.$el.find('#gplayer-cc-menu').css('display')).toBe('none')
|
|
223
|
+
})
|
|
224
|
+
it('should hide subtitle text', () => {
|
|
225
|
+
expect(
|
|
226
|
+
core.activeContainer.$el.find('#gplayer-cc-line').text().trim(),
|
|
227
|
+
).toBe('')
|
|
228
|
+
})
|
|
229
|
+
it('should deactivate subtitle track', () => {
|
|
230
|
+
expect(core.activePlayback.closedCaptionsTrackId).toEqual(-1)
|
|
231
|
+
expect(core.activePlayback.closedCaptionsTracks[0].track.mode).toBe(
|
|
232
|
+
'hidden',
|
|
233
|
+
)
|
|
234
|
+
expect(core.activePlayback.closedCaptionsTracks[1].track.mode).toBe(
|
|
235
|
+
'hidden',
|
|
236
|
+
)
|
|
237
|
+
})
|
|
238
|
+
it('should select menu item', () => {
|
|
239
|
+
expect(
|
|
240
|
+
cc.$el.find('#gplayer-cc-menu li:nth-child(3)').hasClass('current'),
|
|
241
|
+
).toBe(true)
|
|
242
|
+
expect(
|
|
243
|
+
cc.$el
|
|
244
|
+
.find('#gplayer-cc-menu li:nth-child(3) a')
|
|
245
|
+
.attr('aria-checked'),
|
|
246
|
+
).toBe('true')
|
|
247
|
+
expect(cc.$el.find('#gplayer-cc-menu li.current').length).toBe(1)
|
|
248
|
+
expect(
|
|
249
|
+
cc.$el.find('#gplayer-cc-menu li a[aria-checked="true"]').length,
|
|
250
|
+
).toBe(1)
|
|
95
251
|
})
|
|
96
252
|
})
|
|
97
253
|
})
|
|
98
254
|
})
|
|
255
|
+
|
|
256
|
+
function emitSubtitleAvailable(core: any) {
|
|
257
|
+
core.activePlayback.closedCaptionsTracks = [
|
|
258
|
+
{
|
|
259
|
+
id: 1,
|
|
260
|
+
name: 'English',
|
|
261
|
+
track: {
|
|
262
|
+
language: 'en',
|
|
263
|
+
kind: 'subtitles',
|
|
264
|
+
label: 'English',
|
|
265
|
+
mode: 'hidden',
|
|
266
|
+
cues: [],
|
|
267
|
+
},
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
id: 2,
|
|
271
|
+
name: 'Spanish',
|
|
272
|
+
track: {
|
|
273
|
+
language: 'es',
|
|
274
|
+
kind: 'subtitles',
|
|
275
|
+
label: 'Spanish',
|
|
276
|
+
mode: 'hidden',
|
|
277
|
+
cues: [],
|
|
278
|
+
},
|
|
279
|
+
},
|
|
280
|
+
]
|
|
281
|
+
core.activePlayback.emit(Events.PLAYBACK_SUBTITLE_AVAILABLE)
|
|
282
|
+
core.activeContainer.emit(Events.CONTAINER_SUBTITLE_AVAILABLE)
|
|
283
|
+
}
|
|
@@ -1,25 +1,14 @@
|
|
|
1
1
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
2
|
|
|
3
3
|
exports[`ClosedCaptions > basically > should render 1`] = `
|
|
4
|
-
"<button
|
|
5
|
-
<span class="cc-text">/assets/icons/new/subtitles-off.svg</span>
|
|
6
|
-
</button>
|
|
4
|
+
"<button class="media-control-button media-control-icon gcore-skin-button-color media-control-dd" id="gplayer-cc-button" aria-haspopup="menu" aria-expanded="false" aria-controls="gplayer-cc-menu">/assets/icons/new/subtitles-off.svg</button>
|
|
7
5
|
|
|
8
|
-
<ul class="gcore-skin-bg-color" id="cc-
|
|
6
|
+
<ul class="gcore-skin-bg-color media-control-dd__popup" id="gplayer-cc-menu" role="menu" style="display: none; max-height: 211px;">
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
<li class="">
|
|
17
|
-
<a href="#" class="gcore-skin-text-color" data-cc-select="2">
|
|
18
|
-
Spanish
|
|
19
|
-
</a>
|
|
20
|
-
</li>
|
|
21
|
-
|
|
22
|
-
<li class="current"><a href="#" class="gcore-skin-text-color gcore-skin-active" data-cc-select="-1">off</a></li>
|
|
23
|
-
</ul>
|
|
24
|
-
"
|
|
8
|
+
<li class="current">
|
|
9
|
+
<a href="#" class="gcore-skin-text-color gcore-skin-active" data-item="-1" role="menuitemradio" aria-checked="true">
|
|
10
|
+
off
|
|
11
|
+
</a>
|
|
12
|
+
</li>
|
|
13
|
+
</ul>"
|
|
25
14
|
`;
|
package/src/testUtils.ts
CHANGED
|
@@ -134,6 +134,8 @@ export function createMockMediaControl(core: any) {
|
|
|
134
134
|
// @ts-ignore
|
|
135
135
|
mediaControl.getAvailableHeight = vi.fn().mockReturnValue(300)
|
|
136
136
|
// @ts-ignore
|
|
137
|
+
mediaControl.getAvailablePopupHeight = vi.fn().mockReturnValue(286)
|
|
138
|
+
// @ts-ignore
|
|
137
139
|
mediaControl.toggleElement = vi.fn()
|
|
138
140
|
vi.spyOn(mediaControl, 'trigger')
|
|
139
141
|
core.$el.append(mediaControl.$el)
|