@gcorevideo/player 2.25.7 → 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.
Files changed (33) hide show
  1. package/assets/bottom-gear/gear-sub-menu.scss +4 -9
  2. package/assets/media-control/container.scss +0 -13
  3. package/assets/media-control/media-control.scss +14 -12
  4. package/assets/media-control/width270.scss +3 -0
  5. package/assets/media-control/width370.scss +4 -0
  6. package/assets/multi-camera/style.scss +0 -5
  7. package/assets/subtitles/combobox.ejs +27 -6
  8. package/assets/subtitles/string.ejs +1 -1
  9. package/assets/subtitles/style.scss +16 -69
  10. package/dist/core.js +1 -1
  11. package/dist/index.css +642 -696
  12. package/dist/index.embed.js +136 -98
  13. package/dist/index.js +77 -42
  14. package/lib/plugins/bottom-gear/BottomGear.d.ts +1 -1
  15. package/lib/plugins/bottom-gear/BottomGear.d.ts.map +1 -1
  16. package/lib/plugins/bottom-gear/BottomGear.js +3 -4
  17. package/lib/plugins/media-control/MediaControl.d.ts +4 -0
  18. package/lib/plugins/media-control/MediaControl.d.ts.map +1 -1
  19. package/lib/plugins/media-control/MediaControl.js +7 -0
  20. package/lib/plugins/subtitles/ClosedCaptions.d.ts +7 -4
  21. package/lib/plugins/subtitles/ClosedCaptions.d.ts.map +1 -1
  22. package/lib/plugins/subtitles/ClosedCaptions.js +64 -34
  23. package/lib/testUtils.d.ts.map +1 -1
  24. package/lib/testUtils.js +2 -0
  25. package/package.json +1 -1
  26. package/src/plugins/bottom-gear/BottomGear.ts +3 -4
  27. package/src/plugins/bottom-gear/__tests__/BottomGear.test.ts +1 -1
  28. package/src/plugins/media-control/MediaControl.ts +10 -0
  29. package/src/plugins/subtitles/ClosedCaptions.ts +66 -35
  30. package/src/plugins/subtitles/__tests__/ClosedCaptions.test.ts +220 -35
  31. package/src/plugins/subtitles/__tests__/__snapshots__/ClosedCaptions.test.ts.snap +8 -19
  32. package/src/testUtils.ts +2 -0
  33. package/tsconfig.tsbuildinfo +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"testUtils.d.ts","sourceRoot":"","sources":["../src/testUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAK,YAAY,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,MAAM,MAAM,eAAe,CAAA;AAGlC,wBAAgB,cAAc,CAC5B,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACrC,SAAS,GAAE,GAAkC;;;;;;;;;;;;;;;;;EAsB9C;AAED,wBAAgB,gBAAgB;;;EAK/B;AAED,wBAAgB,mBAAmB;;;;;;EAKlC;AAED,wBAAgB,kBAAkB,CAChC,IAAI,SAAS,EACb,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqCtC;AAED,wBAAgB,mBAAmB,CACjC,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACrC,QAAQ,GAAE,GAAgD;;;;;;;;;;;;;;;;;;;;;;;;;EA8B3D;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,GAAG,gBAqB/C;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,GAAG,OAe7C"}
1
+ {"version":3,"file":"testUtils.d.ts","sourceRoot":"","sources":["../src/testUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAK,YAAY,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,MAAM,MAAM,eAAe,CAAA;AAGlC,wBAAgB,cAAc,CAC5B,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACrC,SAAS,GAAE,GAAkC;;;;;;;;;;;;;;;;;EAsB9C;AAED,wBAAgB,gBAAgB;;;EAK/B;AAED,wBAAgB,mBAAmB;;;;;;EAKlC;AAED,wBAAgB,kBAAkB,CAChC,IAAI,SAAS,EACb,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqCtC;AAED,wBAAgB,mBAAmB,CACjC,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACrC,QAAQ,GAAE,GAAgD;;;;;;;;;;;;;;;;;;;;;;;;;EA8B3D;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,GAAG,gBAuB/C;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,GAAG,OAe7C"}
package/lib/testUtils.js CHANGED
@@ -117,6 +117,8 @@ export function createMockMediaControl(core) {
117
117
  // @ts-ignore
118
118
  mediaControl.getAvailableHeight = vi.fn().mockReturnValue(300);
119
119
  // @ts-ignore
120
+ mediaControl.getAvailablePopupHeight = vi.fn().mockReturnValue(286);
121
+ // @ts-ignore
120
122
  mediaControl.toggleElement = vi.fn();
121
123
  vi.spyOn(mediaControl, 'trigger');
122
124
  core.$el.append(mediaControl.$el);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gcorevideo/player",
3
- "version": "2.25.7",
3
+ "version": "2.25.8",
4
4
  "description": "Gcore JavaScript video player",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -198,7 +198,7 @@ export class BottomGear extends UICorePlugin {
198
198
  .appendTo(this.$el.find('#gear-options-wrapper'))
199
199
  $item.on('click', (e: MouseEvent) => {
200
200
  e.stopPropagation()
201
- this.alignSubmenu($subMenu)
201
+ this.clampPopup($subMenu)
202
202
  $subMenu.show()
203
203
  this.$el.find('#gear-options').hide()
204
204
  })
@@ -323,10 +323,9 @@ export class BottomGear extends UICorePlugin {
323
323
  mediaControl.slot('gear', this.$el)
324
324
  }
325
325
 
326
- private alignSubmenu($subMenu: ZeptoResult) {
326
+ private clampPopup($subMenu: ZeptoResult) {
327
327
  const availableHeight =
328
- this.core.getPlugin('media_control').getAvailableHeight() -
329
- MENU_VMARGIN * 2
328
+ this.core.getPlugin('media_control').getAvailablePopupHeight()
330
329
  $subMenu.css('max-height', `${availableHeight}px`)
331
330
  $subMenu
332
331
  .find('.gear-sub-menu')
@@ -110,7 +110,7 @@ describe('BottomGear', () => {
110
110
  })
111
111
  describe('when submenu is open', () => {
112
112
  beforeEach(async () => {
113
- mediaControl.getAvailableHeight.mockReturnValue(198)
113
+ mediaControl.getAvailablePopupHeight.mockReturnValue(174)
114
114
  bottomGear.$el.find('#gear-button').click()
115
115
  await new Promise((resolve) => setTimeout(resolve, 0))
116
116
  bottomGear.$el.find('#more-button').click()
@@ -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 })
@@ -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 template = template(comboboxHTML)
96
+ private static readonly templateControl = template(comboboxHTML)
95
97
 
96
- private static readonly templateString = template(stringHTML)
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-select li a': 'onItemSelect',
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.render) // TODO mount to media control
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
- if (!this.shouldRender()) {
341
- return this
342
- }
343
-
344
- const mediaControl = this.core.getPlugin('media_control')
345
-
346
- this.$el.html(ClosedCaptions.template({ tracks: this.tracks, i18n: this.core.i18n }))
347
- this.$el.find('#cc-select').hide()
348
- this.core.activeContainer.$el.find('#cc-line').remove()
349
- this.$line = $(ClosedCaptions.templateString())
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
- const id = (event.target as HTMLElement).dataset.ccSelect ?? '-1'
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
- trace(`${T} onItemSelect`, { id })
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
- trace(`${T} hideMenu`)
402
- this.$el.find('#cc-select').hide()
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.$el.find('#cc-select').toggle()
411
- // TODO hold state, add aria-expanded to the button, add active state to the button
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
- return this.$el.find(`#cc-select li a[data-cc-select="${id}"]`).parent()
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-select li')
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
- this.$el.find('span.cc-text').html(icon)
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
- // import { Events } from '@clappr/core';
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(mediaControl.slot).toHaveBeenCalledWith('cc', cc.$el)
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
- cc.$el.find('#cc-button').click()
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-select').css('display')).not.toBe('none')
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
- cc.$el.find('#cc-button').click().click()
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-select').css('display')).toBe('none')
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-select').css('display')).toBe('none')
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 data-cc-button="" class="media-control-button media-control-icon gcore-skin-button-color" id="cc-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-select" style="display: none;">
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
- <li class="">
11
- <a href="#" class="gcore-skin-text-color" data-cc-select="1">
12
- English
13
- </a>
14
- </li>
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)