@gcorevideo/player 2.21.3 → 2.21.6

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 (98) hide show
  1. package/assets/audio-selector/style.scss +1 -1
  2. package/assets/audio-selector/track-selector.ejs +3 -3
  3. package/assets/bottom-gear/bottomgear.ejs +2 -2
  4. package/assets/dvr-controls/dvr_controls.scss +7 -25
  5. package/assets/dvr-controls/index.ejs +2 -2
  6. package/assets/media-control/container.scss +1 -1
  7. package/assets/media-control/media-control.ejs +1 -6
  8. package/assets/media-control/media-control.scss +14 -7
  9. package/assets/media-control/width270.scss +1 -1
  10. package/assets/media-control/width370.scss +5 -5
  11. package/assets/playback-rate/button.ejs +2 -2
  12. package/assets/playback-rate/list.ejs +4 -4
  13. package/assets/style/theme.scss +1 -1
  14. package/assets/subtitles/combobox.ejs +5 -5
  15. package/assets/subtitles/string.ejs +1 -1
  16. package/assets/subtitles/style.scss +2 -2
  17. package/dist/core.js +2 -1
  18. package/dist/index.css +993 -993
  19. package/dist/index.js +199 -178
  20. package/dist/player.d.ts +141 -119
  21. package/dist/plugins/index.css +1118 -1118
  22. package/dist/plugins/index.js +191 -173
  23. package/docs/api/player.bottomgear.getelement.md +2 -2
  24. package/docs/api/player.bottomgear.md +1 -1
  25. package/docs/api/{player.subtitles.hide.md → player.closedcaptions.hide.md} +2 -2
  26. package/docs/api/{player.subtitles.md → player.closedcaptions.md} +11 -11
  27. package/docs/api/{player.subtitles.show.md → player.closedcaptions.show.md} +2 -2
  28. package/docs/api/player.closedcaptionspluginsettings.md +13 -0
  29. package/docs/api/player.gearitemelement.md +6 -4
  30. package/docs/api/player.gearoptionsitem.md +16 -0
  31. package/docs/api/player.md +48 -12
  32. package/docs/api/player.mediacontrol.putelement.md +2 -2
  33. package/docs/api/player.mediacontrolelement.md +1 -1
  34. package/docs/api/player.playbackrate.md +1 -1
  35. package/docs/api/player.subtitlespluginsettings.md +18 -0
  36. package/docs/api/player.texttrackitem.id.md +11 -0
  37. package/docs/api/player.texttrackitem.md +87 -0
  38. package/docs/api/player.texttrackitem.name.md +11 -0
  39. package/docs/api/player.texttrackitem.track.md +11 -0
  40. package/lib/index.d.ts +1 -1
  41. package/lib/index.js +1 -1
  42. package/lib/index.plugins.d.ts +2 -1
  43. package/lib/index.plugins.d.ts.map +1 -1
  44. package/lib/index.plugins.js +2 -1
  45. package/lib/playback/dash-playback/DashPlayback.d.ts.map +1 -1
  46. package/lib/playback/dash-playback/DashPlayback.js +1 -0
  47. package/lib/plugins/audio-selector/AudioSelector.d.ts +2 -3
  48. package/lib/plugins/audio-selector/AudioSelector.d.ts.map +1 -1
  49. package/lib/plugins/audio-selector/AudioSelector.js +6 -7
  50. package/lib/plugins/bottom-gear/BottomGear.d.ts +6 -2
  51. package/lib/plugins/bottom-gear/BottomGear.d.ts.map +1 -1
  52. package/lib/plugins/bottom-gear/BottomGear.js +2 -1
  53. package/lib/plugins/dvr-controls/DvrControls.d.ts +0 -3
  54. package/lib/plugins/dvr-controls/DvrControls.d.ts.map +1 -1
  55. package/lib/plugins/dvr-controls/DvrControls.js +13 -38
  56. package/lib/plugins/media-control/MediaControl.d.ts +14 -18
  57. package/lib/plugins/media-control/MediaControl.d.ts.map +1 -1
  58. package/lib/plugins/media-control/MediaControl.js +105 -72
  59. package/lib/plugins/picture-in-picture/PictureInPicture.d.ts +1 -0
  60. package/lib/plugins/picture-in-picture/PictureInPicture.d.ts.map +1 -1
  61. package/lib/plugins/picture-in-picture/PictureInPicture.js +4 -4
  62. package/lib/plugins/playback-rate/PlaybackRate.d.ts +0 -1
  63. package/lib/plugins/playback-rate/PlaybackRate.d.ts.map +1 -1
  64. package/lib/plugins/playback-rate/PlaybackRate.js +23 -14
  65. package/lib/plugins/subtitles/ClosedCaptions.d.ts +118 -0
  66. package/lib/plugins/subtitles/ClosedCaptions.d.ts.map +1 -0
  67. package/lib/plugins/subtitles/ClosedCaptions.js +348 -0
  68. package/lib/plugins/subtitles/Subtitles.d.ts +12 -9
  69. package/lib/plugins/subtitles/Subtitles.d.ts.map +1 -1
  70. package/lib/plugins/subtitles/Subtitles.js +31 -32
  71. package/lib/testUtils.d.ts +26 -19
  72. package/lib/testUtils.d.ts.map +1 -1
  73. package/lib/testUtils.js +30 -45
  74. package/package.json +1 -1
  75. package/src/index.plugins.ts +2 -1
  76. package/src/index.ts +1 -1
  77. package/src/playback/dash-playback/DashPlayback.ts +1 -0
  78. package/src/plugins/audio-selector/AudioSelector.ts +9 -8
  79. package/src/plugins/bottom-gear/BottomGear.ts +11 -4
  80. package/src/plugins/bottom-gear/__tests__/BottomGear.test.ts +1 -1
  81. package/src/plugins/bottom-gear/__tests__/__snapshots__/BottomGear.test.ts.snap +2 -2
  82. package/src/plugins/dvr-controls/DvrControls.ts +16 -44
  83. package/src/plugins/dvr-controls/__tests__/DvrControls.test.ts +18 -22
  84. package/src/plugins/dvr-controls/__tests__/__snapshots__/DvrControls.test.ts.snap +6 -30
  85. package/src/plugins/media-control/MediaControl.ts +130 -85
  86. package/src/plugins/media-control/__tests__/MediaControl.test.ts +132 -0
  87. package/src/plugins/media-control/__tests__/__snapshots__/MediaControl.test.ts.snap +299 -0
  88. package/src/plugins/picture-in-picture/PictureInPicture.ts +5 -5
  89. package/src/plugins/playback-rate/PlaybackRate.ts +142 -100
  90. package/src/plugins/playback-rate/__tests__/PlaybackRate.test.ts +65 -0
  91. package/src/plugins/playback-rate/__tests__/__snapshots__/PlaybackRate.test.ts.snap +11 -0
  92. package/src/plugins/subtitles/{Subtitles.ts → ClosedCaptions.ts} +42 -34
  93. package/src/plugins/subtitles/__tests__/ClosedCaptions.test.ts +58 -0
  94. package/src/plugins/subtitles/__tests__/__snapshots__/ClosedCaptions.test.ts.snap +25 -0
  95. package/src/testUtils.ts +30 -45
  96. package/temp/player.api.json +269 -89
  97. package/tsconfig.tsbuildinfo +1 -1
  98. package/src/plugins/index.ts +0 -39
@@ -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
- ['DVR behind live edge', true, true, true],
32
- ])('%s', (_, dvrEnabled, dvrInUse, indicateDvr) => {
32
+ ])('%s', (_, dvrEnabled, dvrInUse) => {
33
33
  beforeEach(() => {
34
34
  core.activePlayback.dvrEnabled = dvrEnabled
35
- core.trigger('core:ready')
36
- core.trigger('core:active:container:changed')
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.activeContainer.trigger('container:dvr', true)
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 render to the media control left panel', () => {
46
- expect(mediaControl.$el.find('.media-control-left-panel').text()).toContain('live')
47
- expect(mediaControl.el.innerHTML).toMatchSnapshot()
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 indicate live streaming mode', () => {
50
- expect(mediaControl.$el.hasClass('live')).toBe(true)
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(() => {
@@ -78,11 +72,13 @@ describe('DvrControls', () => {
78
72
  })
79
73
  describe('VOD stream', () => {
80
74
  beforeEach(() => {
81
- core.getPlaybackType.mockReturnValue('vod')
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('core:ready')
85
- core.trigger('core:active:container:changed')
80
+ core.trigger(Events.CORE_READY)
81
+ core.trigger(Events.CORE_ACTIVE_CONTAINER_CHANGED, core.activeContainer)
86
82
  })
87
83
  it('should not render', () => {
88
84
  expect(dvrControls.el.textContent).toBeFalsy()
@@ -1,43 +1,19 @@
1
1
  // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
3
  exports[`DvrControls > live stream > DVR at live edge > should render 1`] = `
4
- "<div class="live-info">live</div>
5
- <button type="button" class="live-button" aria-label="back_to_live">back_to_live</button>
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 to the media control left panel 1`] = `
10
- "<div class="media-control-left-panel" data-media-control=""><div class="dvr-controls" data-dvr-controls=""><div class="live-info">live</div>
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
9
  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>
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
- `;
@@ -42,13 +42,30 @@ import fullscreenOnIcon from '../../../assets/icons/new/fullscreen-on.svg'
42
42
  * @beta
43
43
  */
44
44
  export type MediaControlElement =
45
- | 'audioTracksSelector'
45
+ | 'audiotracks'
46
+ | 'cc'
46
47
  | 'clipText'
48
+ | 'dvr'
49
+ | 'duration'
47
50
  | 'gear'
48
51
  | 'pip'
49
52
  | 'playbackRate'
53
+ | 'position'
50
54
  | 'seekBarContainer'
51
- | 'subtitlesSelector'
55
+
56
+ type MediaControlSettings = {
57
+ left: MediaControlElement[]
58
+ right: MediaControlElement[]
59
+ default: MediaControlElement[]
60
+ seekEnabled: boolean
61
+ }
62
+
63
+ const DEFAULT_SETTINGS: MediaControlSettings = {
64
+ left: [],
65
+ right: [],
66
+ default: [],
67
+ seekEnabled: true,
68
+ }
52
69
 
53
70
  /**
54
71
  * Custom events emitted by the plugins to communicate with one another
@@ -66,7 +83,8 @@ const T = 'plugins.media_control'
66
83
  const LEFT_ORDER = [
67
84
  'playpause',
68
85
  'playstop',
69
- 'live',
86
+ // 'live',
87
+ 'dvr',
70
88
  'volume',
71
89
  'position',
72
90
  'duration',
@@ -95,7 +113,7 @@ type DisabledClickable = {
95
113
  * The methods exposed are to be used by the other plugins that extend the media control UI.
96
114
  */
97
115
  export class MediaControl extends UICorePlugin {
98
- private advertisementPlaying = false
116
+ // private advertisementPlaying = false
99
117
 
100
118
  private buttonsColor: string | null = null
101
119
 
@@ -118,8 +136,6 @@ export class MediaControl extends UICorePlugin {
118
136
 
119
137
  private intendedVolume = 100
120
138
 
121
- private isHD = false
122
-
123
139
  private keepVisible = false
124
140
 
125
141
  private kibo: Kibo
@@ -131,7 +147,7 @@ export class MediaControl extends UICorePlugin {
131
147
 
132
148
  private rendered = false
133
149
 
134
- private settings: Record<string, unknown> = {}
150
+ private settings: MediaControlSettings = DEFAULT_SETTINGS
135
151
 
136
152
  private userDisabled = false
137
153
 
@@ -320,8 +336,6 @@ export class MediaControl extends UICorePlugin {
320
336
  * @internal
321
337
  */
322
338
  override bindEvents() {
323
- // @ts-ignore
324
- this.stopListening()
325
339
  this.listenTo(
326
340
  this.core,
327
341
  Events.CORE_ACTIVE_CONTAINER_CHANGED,
@@ -394,17 +408,17 @@ export class MediaControl extends UICorePlugin {
394
408
  this.listenTo(
395
409
  this.core.activeContainer,
396
410
  Events.CONTAINER_SETTINGSUPDATE,
397
- this.settingsUpdate,
411
+ this.updateSettings,
398
412
  )
399
413
  this.listenTo(
400
414
  this.core.activeContainer,
401
415
  Events.CONTAINER_PLAYBACKDVRSTATECHANGED,
402
- this.settingsUpdate,
416
+ this.onDvrStateChanged,
403
417
  )
404
418
  this.listenTo(
405
419
  this.core.activeContainer,
406
420
  Events.CONTAINER_HIGHDEFINITIONUPDATE,
407
- this.highDefinitionUpdate,
421
+ this.onHdUpdate,
408
422
  )
409
423
  this.listenTo(
410
424
  this.core.activeContainer,
@@ -427,14 +441,12 @@ export class MediaControl extends UICorePlugin {
427
441
  Events.CONTAINER_OPTIONS_CHANGE,
428
442
  this.setInitialVolume,
429
443
  )
430
- if (this.core.activePlayback.el.nodeName.toLowerCase() === 'video') {
431
- // wait until the metadata has loaded and then check if fullscreen on video tag is supported
432
- this.listenToOnce(
433
- this.core.activeContainer,
434
- Events.CONTAINER_LOADEDMETADATA,
435
- this.onLoadedMetadataOnVideoTag,
436
- )
437
- }
444
+ // wait until the metadata has loaded and then check if fullscreen on video tag is supported
445
+ this.listenToOnce(
446
+ this.core.activeContainer,
447
+ Events.CONTAINER_LOADEDMETADATA,
448
+ this.onLoadedMetadata,
449
+ )
438
450
  }
439
451
 
440
452
  /**
@@ -475,14 +487,19 @@ export class MediaControl extends UICorePlugin {
475
487
  this.updateVolumeUI()
476
488
  }
477
489
 
478
- private onLoadedMetadataOnVideoTag(event: any) {
490
+ private onLoadedMetadata() {
479
491
  const video = this.core.activePlayback?.el
480
492
 
481
493
  // video.webkitSupportsFullscreen is deprecated but iOS appears to only use this
482
494
  // see https://github.com/clappr/clappr/issues/1127
483
495
  if (!Fullscreen.fullscreenEnabled() && video.webkitSupportsFullscreen) {
484
496
  this.fullScreenOnVideoTagSupported = true
485
- this.settingsUpdate()
497
+ }
498
+ this.updateSettings()
499
+ if (this.core.activeContainer.getPlaybackType() === Playback.LIVE) {
500
+ this.$el.addClass('live')
501
+ } else {
502
+ this.$el.removeClass('live')
486
503
  }
487
504
  }
488
505
 
@@ -493,8 +510,6 @@ export class MediaControl extends UICorePlugin {
493
510
  }
494
511
 
495
512
  assert.ok(this.$volumeBarContainer, 'volume bar container must be present')
496
- // update volume bar scrubber/fill on bar mode
497
- // this.$volumeBarContainer.find('.bar-fill-2').css({});
498
513
  const containerWidth = this.$volumeBarContainer.width()
499
514
 
500
515
  assert.ok(
@@ -720,17 +735,18 @@ export class MediaControl extends UICorePlugin {
720
735
  // if the container is not ready etc
721
736
  this.intendedVolume = value
722
737
  this.persistConfig && !isInitialVolume && Config.persist('volume', value)
738
+ // TODO
723
739
  const setWhenContainerReady = () => {
724
- if (this.container && this.container.isReady) {
725
- this.container.setVolume(value)
740
+ if (this.core.activeContainer && this.core.activeContainer.isReady) {
741
+ this.core.activeContainer.setVolume(value)
726
742
  } else {
727
- this.listenToOnce(this.container, Events.CONTAINER_READY, () => {
728
- this.container.setVolume(value)
743
+ this.listenToOnce(this.core.activeContainer, Events.CONTAINER_READY, () => {
744
+ this.core.activeContainer.setVolume(value)
729
745
  })
730
746
  }
731
747
  }
732
748
 
733
- if (!this.container) {
749
+ if (!this.core.activeContainer) {
734
750
  this.listenToOnce(this, Events.MEDIACONTROL_CONTAINERCHANGED, () =>
735
751
  setWhenContainerReady(),
736
752
  )
@@ -742,7 +758,7 @@ export class MediaControl extends UICorePlugin {
742
758
  private toggleFullscreen() {
743
759
  if (!Browser.isMobile) {
744
760
  this.trigger(Events.MEDIACONTROL_FULLSCREEN, this.name)
745
- this.container.fullscreen()
761
+ this.core.activeContainer.fullscreen()
746
762
  this.core.toggleFullscreen()
747
763
  this.resetUserKeepVisible()
748
764
  }
@@ -754,7 +770,8 @@ export class MediaControl extends UICorePlugin {
754
770
  this.setInitialVolume()
755
771
  this.changeTogglePlay()
756
772
  this.bindContainerEvents()
757
- this.settingsUpdate()
773
+ this.updateSettings()
774
+ // TODO remove
758
775
  this.core.activeContainer.trigger(
759
776
  Events.CONTAINER_PLAYBACKDVRSTATECHANGED,
760
777
  this.core.activeContainer.isDvrInUse(),
@@ -849,9 +866,9 @@ export class MediaControl extends UICorePlugin {
849
866
  // default to 100%
850
867
  this.currentSeekBarPercentage = 100
851
868
  if (
852
- this.container &&
853
- (this.container.getPlaybackType() !== Playback.LIVE ||
854
- this.container.isDvrInUse())
869
+ this.core.activeContainer &&
870
+ (this.core.activeContainer.getPlaybackType() !== Playback.LIVE ||
871
+ this.core.activeContainer.isDvrInUse())
855
872
  ) {
856
873
  this.currentSeekBarPercentage =
857
874
  (this.currentPositionValue / this.currentDurationValue) * 100
@@ -887,21 +904,13 @@ export class MediaControl extends UICorePlugin {
887
904
  let pos = (offsetX / this.$seekBarContainer.width()) * 100
888
905
 
889
906
  pos = Math.min(100, Math.max(pos, 0))
890
- this.container && this.container.seekPercentage(pos)
907
+ this.core.activeContainer && this.core.activeContainer.seekPercentage(pos)
891
908
 
892
909
  this.setSeekPercentage(pos)
893
910
 
894
911
  return false
895
912
  }
896
913
 
897
- private setKeepVisible() {
898
- this.keepVisible = true
899
- }
900
-
901
- private resetKeepVisible() {
902
- this.keepVisible = false
903
- }
904
-
905
914
  private setUserKeepVisible() {
906
915
  this.userKeepVisible = true
907
916
  }
@@ -989,7 +998,7 @@ export class MediaControl extends UICorePlugin {
989
998
  }
990
999
  }
991
1000
 
992
- private settingsUpdate() {
1001
+ private updateSettings() {
993
1002
  const newSettings = $.extend(
994
1003
  true,
995
1004
  {
@@ -997,19 +1006,28 @@ export class MediaControl extends UICorePlugin {
997
1006
  default: [],
998
1007
  right: [],
999
1008
  },
1000
- this.core.activeContainer?.settings,
1009
+ this.core.activeContainer.settings,
1001
1010
  )
1002
1011
 
1012
+ // TODO make order controlled via CSS
1003
1013
  newSettings.left = orderByOrderPattern(
1004
1014
  [...newSettings.left, 'clipsText', 'volume'],
1005
1015
  LEFT_ORDER,
1006
1016
  )
1007
1017
 
1018
+ if (
1019
+ this.core.activePlayback.getPlaybackType() === Playback.LIVE &&
1020
+ this.core.activePlayback.dvrEnabled
1021
+ ) {
1022
+ newSettings.left.push('dvr')
1023
+ }
1024
+
1025
+ // actual order of the items appear rendered is controlled by CSS
1008
1026
  newSettings.right = [
1009
1027
  'fullscreen',
1010
1028
  'pip',
1011
- 'bottomgear',
1012
- 'subtitles',
1029
+ 'gear',
1030
+ 'cc',
1013
1031
  'multicamera',
1014
1032
  'playbackrate',
1015
1033
  'vr',
@@ -1021,7 +1039,7 @@ export class MediaControl extends UICorePlugin {
1021
1039
  !Fullscreen.fullscreenEnabled()) ||
1022
1040
  this.options.fullscreenDisable
1023
1041
  ) {
1024
- // remove fullscreen from settings if it is present
1042
+ // remove fullscreen from settings if it is not available
1025
1043
  removeArrayItem(newSettings.default, 'fullscreen')
1026
1044
  removeArrayItem(newSettings.left, 'fullscreen')
1027
1045
  removeArrayItem(newSettings.right, 'fullscreen')
@@ -1030,12 +1048,13 @@ export class MediaControl extends UICorePlugin {
1030
1048
  removeArrayItem(newSettings.default, 'hd-indicator')
1031
1049
  removeArrayItem(newSettings.left, 'hd-indicator')
1032
1050
 
1051
+ // TODO get from container's settings
1033
1052
  if (this.core.activePlayback.name === 'html5_video') {
1034
1053
  newSettings.seekEnabled = this.isSeekEnabledForHtml5Playback()
1035
1054
  }
1036
1055
 
1037
1056
  const settingsChanged =
1038
- JSON.stringify(this.settings) !== JSON.stringify(newSettings)
1057
+ serializeSettings(this.settings) !== serializeSettings(newSettings)
1039
1058
 
1040
1059
  if (settingsChanged) {
1041
1060
  this.settings = newSettings
@@ -1043,8 +1062,8 @@ export class MediaControl extends UICorePlugin {
1043
1062
  }
1044
1063
  }
1045
1064
 
1046
- private highDefinitionUpdate(isHD: boolean) {
1047
- this.isHD = isHD
1065
+ private onHdUpdate(isHD: boolean) {
1066
+ // TODO render?
1048
1067
  }
1049
1068
 
1050
1069
  private createCachedElements() {
@@ -1078,7 +1097,7 @@ export class MediaControl extends UICorePlugin {
1078
1097
  this.$multiCameraSelector = this.$el.find(
1079
1098
  '.media-control-multicamera[data-multicamera]',
1080
1099
  )
1081
- this.$clipText = this.$el.find('.media-clip-text[data-clipstext]')
1100
+ this.$clipText = this.$el.find('.media-clip-text[data-clipstext]') // TODO
1082
1101
  this.$clipTextContainer = this.$el.find(
1083
1102
  '.media-clip-container[data-clipstext]',
1084
1103
  )
@@ -1108,57 +1127,53 @@ export class MediaControl extends UICorePlugin {
1108
1127
  */
1109
1128
  getElement(name: MediaControlElement): ZeptoResult | null {
1110
1129
  switch (name) {
1111
- case 'audioTracksSelector':
1130
+ case 'audiotracks':
1112
1131
  return null
1113
1132
  case 'clipText':
1114
1133
  return this.$clipText
1115
- case 'gear':
1116
- return null
1117
- case 'pip':
1118
- return null
1119
1134
  case 'playbackRate':
1120
1135
  return this.$playbackRate
1121
1136
  case 'seekBarContainer':
1122
1137
  return this.$seekBarContainer
1123
- case 'subtitlesSelector':
1124
- return null
1125
1138
  }
1126
1139
  }
1127
1140
 
1128
- putElement(name: MediaControlElement, element: ZeptoResult) {
1129
- switch (name) {
1130
- case 'audioTracksSelector':
1131
- this.getRightPanel().append(element)
1132
- break
1133
- case 'gear':
1134
- this.getRightPanel().append(element)
1135
- break
1136
- case 'pip':
1137
- this.getRightPanel().append(element)
1138
- break
1139
- case 'subtitlesSelector':
1140
- this.getRightPanel().append(element)
1141
- break
1141
+ putElement(name: MediaControlElement, element: HTMLElement) {
1142
+ const panel = this.getElementLocation(name)
1143
+ trace(`${T} putElement`, { name, panel: !!panel })
1144
+ if (panel) {
1145
+ const current = panel.find(`[data-${name}]`)
1146
+ element.setAttribute(`data-${name}`, '')
1147
+ // TODO test
1148
+ if (current.length) {
1149
+ if (current[0] === element) {
1150
+ return
1151
+ }
1152
+ current.replaceWith(element)
1153
+ } else {
1154
+ panel.append(element)
1155
+ }
1142
1156
  }
1143
1157
  }
1144
1158
 
1145
1159
  /**
1146
- * Get the right panel area to append custom elements to
1147
- * @returns ZeptoSelector of the right panel element
1160
+ * Toggle the visibility of a media control element
1161
+ * @param name - The name of the media control element
1162
+ * @param show - Whether to show or hide the element
1148
1163
  */
1149
- getRightPanel() {
1164
+ toggleElement(name: MediaControlElement, show: boolean) {
1165
+ this.$el.find(`[data-${name}]`).toggle(show)
1166
+ }
1167
+
1168
+ private getRightPanel() {
1150
1169
  return this.$el.find('.media-control-right-panel')
1151
1170
  }
1152
1171
 
1153
- /**
1154
- * Get the left panel area to append custom elements to
1155
- * @returns ZeptoSelector of the left panel element
1156
- */
1157
- getLeftPanel() {
1172
+ private getLeftPanel() {
1158
1173
  return this.$el.find('.media-control-left-panel')
1159
1174
  }
1160
1175
 
1161
- getCenterPanel() {
1176
+ private getCenterPanel() {
1162
1177
  return this.$el.find('.media-control-center-panel')
1163
1178
  }
1164
1179
 
@@ -1395,7 +1410,6 @@ export class MediaControl extends UICorePlugin {
1395
1410
  }, 0)
1396
1411
 
1397
1412
  this.parseColors()
1398
- this.highDefinitionUpdate(this.isHD)
1399
1413
 
1400
1414
  this.core.$el.append(this.el)
1401
1415
 
@@ -1424,13 +1438,13 @@ export class MediaControl extends UICorePlugin {
1424
1438
 
1425
1439
  // TODO manage by the ads plugin
1426
1440
  private onStartAd() {
1427
- this.advertisementPlaying = true
1441
+ // this.advertisementPlaying = true
1428
1442
  this.disable()
1429
1443
  }
1430
1444
 
1431
1445
  // TODO manage by the ads plugin
1432
1446
  private onFinishAd() {
1433
- this.advertisementPlaying = false
1447
+ // this.advertisementPlaying = false
1434
1448
  this.enable()
1435
1449
  }
1436
1450
 
@@ -1487,8 +1501,39 @@ export class MediaControl extends UICorePlugin {
1487
1501
 
1488
1502
  return isFinite(this.core.activePlayback.getDuration())
1489
1503
  }
1504
+
1505
+ private getElementLocation(name: MediaControlElement) {
1506
+ if (this.settings.right?.includes(name)) {
1507
+ return this.getRightPanel()
1508
+ }
1509
+ if (this.settings.left?.includes(name)) {
1510
+ return this.getLeftPanel()
1511
+ }
1512
+ if (this.settings.default?.includes(name)) {
1513
+ return this.getCenterPanel()
1514
+ }
1515
+ return null
1516
+ }
1517
+
1518
+ private onDvrStateChanged(dvrInUse: boolean) {
1519
+ if (dvrInUse) {
1520
+ this.$el.addClass('dvr')
1521
+ } else {
1522
+ this.$el.removeClass('dvr')
1523
+ }
1524
+ }
1490
1525
  }
1491
1526
 
1492
1527
  MediaControl.extend = function (properties) {
1493
1528
  return extend(MediaControl, properties)
1494
1529
  }
1530
+
1531
+ function serializeSettings(s: MediaControlSettings) {
1532
+ return s.left
1533
+ .slice()
1534
+ .sort()
1535
+ .concat(s.right.slice().sort())
1536
+ .concat(s.default.slice().sort())
1537
+ .concat([s.seekEnabled as any])
1538
+ .join(',')
1539
+ }