@gcorevideo/player 2.24.0 → 2.24.2

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 (40) hide show
  1. package/assets/bottom-gear/gear-sub-menu.scss +1 -0
  2. package/dist/core.js +1 -1
  3. package/dist/index.css +761 -760
  4. package/dist/index.js +70 -76
  5. package/dist/player.d.ts +46 -1
  6. package/docs/api/player.cmcdconfig._constructor_.md +50 -0
  7. package/docs/api/player.cmcdconfig.bindevents.md +19 -0
  8. package/docs/api/player.cmcdconfig.exportids.md +21 -0
  9. package/docs/api/player.cmcdconfig.md +191 -0
  10. package/docs/api/player.cmcdconfig.name.md +15 -0
  11. package/docs/api/player.cmcdconfig.supportedversion.md +14 -0
  12. package/docs/api/player.cmcdconfig.version.md +14 -0
  13. package/docs/api/player.cmcdconfigpluginsettings.md +18 -0
  14. package/docs/api/player.md +22 -0
  15. package/lib/plugins/bottom-gear/BottomGear.d.ts +1 -0
  16. package/lib/plugins/bottom-gear/BottomGear.d.ts.map +1 -1
  17. package/lib/plugins/bottom-gear/BottomGear.js +17 -17
  18. package/lib/plugins/cmcd-config/CmcdConfig.d.ts +8 -8
  19. package/lib/plugins/cmcd-config/CmcdConfig.d.ts.map +1 -1
  20. package/lib/plugins/cmcd-config/CmcdConfig.js +43 -47
  21. package/lib/plugins/cmcd-config/utils.d.ts +0 -1
  22. package/lib/plugins/cmcd-config/utils.d.ts.map +1 -1
  23. package/lib/plugins/cmcd-config/utils.js +0 -9
  24. package/lib/plugins/media-control/MediaControl.d.ts +7 -0
  25. package/lib/plugins/media-control/MediaControl.d.ts.map +1 -1
  26. package/lib/plugins/media-control/MediaControl.js +14 -5
  27. package/lib/testUtils.d.ts +1 -0
  28. package/lib/testUtils.d.ts.map +1 -1
  29. package/lib/testUtils.js +3 -0
  30. package/package.json +1 -1
  31. package/src/plugins/bottom-gear/BottomGear.ts +40 -28
  32. package/src/plugins/bottom-gear/__tests__/BottomGear.test.ts +34 -7
  33. package/src/plugins/bottom-gear/__tests__/__snapshots__/BottomGear.test.ts.snap +5 -2
  34. package/src/plugins/cmcd-config/CmcdConfig.ts +57 -57
  35. package/src/plugins/cmcd-config/__tests__/CmcdConfig.test.ts +96 -84
  36. package/src/plugins/cmcd-config/utils.ts +0 -10
  37. package/src/plugins/media-control/MediaControl.ts +18 -6
  38. package/src/testUtils.ts +3 -0
  39. package/temp/player.api.json +243 -0
  40. package/tsconfig.tsbuildinfo +1 -1
@@ -31,6 +31,15 @@ describe('BottomGear', () => {
31
31
  bottomGear.on(GearEvents.RENDERED, onGearRendered, null)
32
32
  core.emit(Events.CORE_READY)
33
33
  bottomGear.addItem('test', null).html('<button>test</button>')
34
+ const $moreOptions = $(
35
+ `<div>
36
+ <button id="more-options-back">&lt; back</button>
37
+ <ul class="gear-sub-menu" id="more-options"><li>Item</li><li>Item</li><li>Item</li></ul>
38
+ </div>`,
39
+ )
40
+ bottomGear
41
+ .addItem('more', $moreOptions)
42
+ .html('<button id="more-button">more options</button>')
34
43
  })
35
44
  it('should render', () => {
36
45
  expect(bottomGear.el.innerHTML).toMatchSnapshot()
@@ -99,6 +108,26 @@ describe('BottomGear', () => {
99
108
  )
100
109
  })
101
110
  })
111
+ describe('when submenu is open', () => {
112
+ beforeEach(async () => {
113
+ mediaControl.getAvailableHeight.mockReturnValue(198)
114
+ bottomGear.$el.find('#gear-button').click()
115
+ await new Promise((resolve) => setTimeout(resolve, 0))
116
+ bottomGear.$el.find('#more-button').click()
117
+ await new Promise((resolve) => setTimeout(resolve, 0))
118
+ })
119
+ it('should show submenu', () => {
120
+ expect(
121
+ bottomGear.$el.find('#more-options').parent().css('display'),
122
+ ).not.toBe('none')
123
+ })
124
+ it('should align nicely within container', () => {
125
+ const submenu = bottomGear.$el.find('#more-options')
126
+ const wrapper = submenu.parent()
127
+ expect(wrapper.css('max-height')).toBe('174px') // available height minus vertical margins
128
+ expect(submenu.css('max-height')).toBe('130px') // wrapper height minus backlink height
129
+ })
130
+ })
102
131
  })
103
132
  describe('when there are no items', () => {
104
133
  beforeEach(() => {
@@ -128,9 +157,9 @@ describe('BottomGear', () => {
128
157
  await new Promise((resolve) => setTimeout(resolve, 0))
129
158
  })
130
159
  it('should collapse the gear menu', () => {
131
- expect(bottomGear.$el.find('#gear-options-wrapper').css('display')).toBe(
132
- 'none',
133
- )
160
+ expect(
161
+ bottomGear.$el.find('#gear-options-wrapper').css('display'),
162
+ ).toBe('none')
134
163
  expect(bottomGear.$el.find('#gear-button').attr('aria-expanded')).toBe(
135
164
  'false',
136
165
  )
@@ -140,14 +169,12 @@ describe('BottomGear', () => {
140
169
  describe('when submenu is open', () => {
141
170
  beforeEach(async () => {
142
171
  // bottomGear.$el.find('#test-submenu').click()
143
- bottomGear.$el.find('#test-options').show(); // as if it was clicked
172
+ bottomGear.$el.find('#test-options').show() // as if it was clicked
144
173
  await new Promise((resolve) => setTimeout(resolve, 0))
145
174
  mediaControl.container.trigger(Events.CONTAINER_CLICK)
146
175
  })
147
176
  it('should collapse it as well', () => {
148
- expect(bottomGear.$el.find('#test-options').css('display')).toBe(
149
- 'none',
150
- )
177
+ expect(bottomGear.$el.find('#test-options').css('display')).toBe('none')
151
178
  expect(bottomGear.$el.find('#gear-options').css('display')).not.toBe(
152
179
  'none',
153
180
  )
@@ -5,7 +5,10 @@ exports[`BottomGear > basically > should render 1`] = `
5
5
  /assets/icons/new/gear.svg
6
6
  </button>
7
7
  <div class="gear-wrapper gcore-skin-bg-color" id="gear-options-wrapper" style="display: none;">
8
- <ul class="gear-options-list" id="gear-options" role="menu"><li data-test=""><button>test</button></li></ul>
9
- </div>
8
+ <ul class="gear-options-list" id="gear-options" role="menu"><li data-test=""><button>test</button></li><li data-more=""><button id="more-button">more options</button></li></ul>
9
+ <div class="gear-sub-menu-wrapper" style="display: none;">
10
+ <button id="more-options-back">&lt; back</button>
11
+ <ul class="gear-sub-menu" id="more-options"><li>Item</li><li>Item</li><li>Item</li></ul>
12
+ </div></div>
10
13
  "
11
14
  `;
@@ -1,10 +1,10 @@
1
- import {
2
- Core,
3
- CorePlugin,
4
- Events,
5
- } from '@clappr/core'
1
+ import { $, Container, Core, CorePlugin, Events } from '@clappr/core'
6
2
 
7
- import { generateContentId, generateSessionId } from './utils'
3
+ // import { trace } from '@gcorevideo/utils'
4
+
5
+ import { generateSessionId } from './utils'
6
+ import { CLAPPR_VERSION } from '../../build.js'
7
+ import { CoreOptions } from 'src/internal.types'
8
8
 
9
9
  const CMCD_KEYS = [
10
10
  'br',
@@ -36,12 +36,14 @@ export type CmcdConfigPluginSettings = {
36
36
  */
37
37
  sessionId: string
38
38
  /**
39
- * Content ID, either constant or derived from current source.
40
- * If ommitted, a SHA-1 hash of current source URL will be used
39
+ * Content ID,
40
+ * If ommitted, the pathname part of the first source URL will be used
41
41
  */
42
- contentId?: string | ((sourceUrl: string, mimeType?: string) => (string | Promise<string>))
42
+ contentId?: string
43
43
  }
44
44
 
45
+ // const T = 'plugins.cmcd'
46
+
45
47
  /**
46
48
  * A `PLUGIN` that configures CMCD for playback
47
49
  * @beta
@@ -61,63 +63,73 @@ export class CmcdConfig extends CorePlugin {
61
63
  return 'cmcd'
62
64
  }
63
65
 
66
+ get version() {
67
+ return '0.1.0'
68
+ }
69
+
70
+ get supportedVersion() {
71
+ return CLAPPR_VERSION
72
+ }
73
+
64
74
  constructor(core: Core) {
65
75
  super(core)
66
76
  this.sid = this.options.cmcd?.sessionId ?? generateSessionId()
77
+ this.cid = this.options.cmcd?.contentId ?? this.generateContentId()
67
78
  }
68
79
 
69
80
  /**
70
81
  * @inheritdocs
71
82
  */
72
83
  override bindEvents() {
73
- this.listenTo(this.core, Events.CORE_ACTIVE_CONTAINER_CHANGED, () =>
74
- this.updateSettings(),
84
+ this.listenTo(this.core, Events.CORE_CONTAINERS_CREATED, () =>
85
+ this.updateSettings(this.core.containers[0]),
75
86
  )
76
87
  }
77
88
 
78
- async getIds(): Promise<{ sid: string; cid: string }> {
89
+ exportIds(): { sid: string; cid: string } {
79
90
  return {
80
91
  sid: this.sid,
81
- cid: await this.ensureContentId(),
92
+ cid: this.cid,
82
93
  }
83
94
  }
84
95
 
85
- private updateSettings() {
86
- switch (this.core.activeContainer.playback.name) {
96
+ private async updateSettings(container: Container) {
97
+ switch (container.playback.name) {
87
98
  case 'dash':
88
- this.updateDashjsSettings()
99
+ $.extend(true, container.playback.options, {
100
+ dash: {
101
+ cmcd: {
102
+ enabled: true,
103
+ enabledKeys: CMCD_KEYS,
104
+ sid: this.sid,
105
+ cid: this.cid,
106
+ },
107
+ },
108
+ })
89
109
  break
90
110
  case 'hls':
91
- this.updateHlsjsSettings()
111
+ $.extend(true, container.playback.options, {
112
+ playback: {
113
+ hlsjsConfig: {
114
+ cmcd: {
115
+ includeKeys: CMCD_KEYS,
116
+ sessionId: this.sid,
117
+ contentId: this.cid,
118
+ },
119
+ },
120
+ },
121
+ })
92
122
  break
93
123
  }
94
124
  }
95
125
 
96
- private async updateDashjsSettings() {
97
- const {cid, sid} = await this.getIds()
98
- const options = this.core.activePlayback.options
99
- this.core.activePlayback.options = {
100
- ...options,
101
- dash: {
102
- ...(options.dash ?? {}),
103
- cmcd: {
104
- enabled: true,
105
- enabledKeys: CMCD_KEYS,
106
- sid,
107
- cid,
108
- },
109
- },
110
- }
111
- }
112
-
113
- private async updateHlsjsSettings() {
114
- const { cid, sid } = await this.getIds()
115
- const options = this.core.activePlayback.options
116
- this.core.activePlayback.options = {
117
- ...options,
126
+ private updateHlsjsSettings(
127
+ options: CoreOptions,
128
+ { cid, sid }: { cid: string; sid: string },
129
+ ) {
130
+ $.extend(true, options, {
118
131
  playback: {
119
132
  hlsjsConfig: {
120
- ...(options.playback?.hlsjsConfig ?? {}),
121
133
  cmcd: {
122
134
  includeKeys: CMCD_KEYS,
123
135
  sessionId: sid,
@@ -125,24 +137,12 @@ export class CmcdConfig extends CorePlugin {
125
137
  },
126
138
  },
127
139
  },
128
- }
140
+ })
129
141
  }
130
142
 
131
- private async ensureContentId(): Promise<string> {
132
- if (!this.cid) {
133
- this.cid = await this.evalContentId()
134
- }
135
- return this.cid
136
- }
137
-
138
- private async evalContentId(): Promise<string> {
139
- if (!this.core.activeContainer.options.cmcd?.contentId) {
140
- return generateContentId(this.core.activePlayback.options.src)
141
- }
142
- const contentId = this.core.activeContainer.options.cmcd.contentId
143
- if (typeof contentId === 'string') {
144
- return contentId
145
- }
146
- return Promise.resolve(contentId(this.core.activePlayback.options.src))
143
+ private generateContentId() {
144
+ return new URL(
145
+ this.core.options.source ?? this.core.options.sources[0].source,
146
+ ).pathname.slice(0, 64)
147
147
  }
148
148
  }
@@ -3,13 +3,9 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
3
3
  import { CmcdConfig } from '../CmcdConfig'
4
4
  import { createMockCore } from '../../../testUtils'
5
5
  import { Events } from '@clappr/core'
6
- import { generateContentId } from '../utils'
7
-
8
- import { createHash } from 'node:crypto'
9
6
 
10
7
  vi.mock('../utils', () => ({
11
8
  generateSessionId: vi.fn().mockReturnValue('123'),
12
- generateContentId: vi.fn().mockResolvedValue('deadbeef'),
13
9
  }))
14
10
 
15
11
  const CMCD_KEYS = [
@@ -38,69 +34,78 @@ describe('CmcdConfig', () => {
38
34
  let plugin: CmcdConfig
39
35
  describe('basically', () => {
40
36
  beforeEach(() => {
41
- core = createMockCore({})
37
+ core = createMockCore({
38
+ sources: [
39
+ {
40
+ source: 'https://zulu.com/123.mpd',
41
+ mimeType: 'application/dash+xml',
42
+ },
43
+ ],
44
+ })
42
45
  })
43
- describe('when active container is changed', () => {
46
+ describe('when container is created', () => {
44
47
  describe('dash.js', () => {
45
48
  beforeEach(async () => {
46
- core.activeContainer.playback.name = 'dash'
47
- core.activeContainer.playback.options.src = 'https://123.mpd'
49
+ core.containers[0].playback.name = 'dash'
48
50
  plugin = new CmcdConfig(core)
49
- core.trigger(Events.CORE_ACTIVE_CONTAINER_CHANGED)
50
- await new Promise(resolve => setTimeout(resolve, 0))
51
+ core.trigger(Events.CORE_CONTAINERS_CREATED)
52
+ await new Promise((resolve) => setTimeout(resolve, 0))
51
53
  })
52
54
  it('should update DASH.js CMCD settings', () => {
53
- expect(core.activePlayback.options).toEqual(expect.objectContaining({
54
- dash: expect.objectContaining({
55
- cmcd: expect.objectContaining({
56
- enabled: true,
57
- enabledKeys: CMCD_KEYS,
58
- })
59
- })
60
- }))
55
+ expect(core.containers[0].playback.options).toEqual(
56
+ expect.objectContaining({
57
+ dash: expect.objectContaining({
58
+ cmcd: expect.objectContaining({
59
+ enabled: true,
60
+ enabledKeys: CMCD_KEYS,
61
+ }),
62
+ }),
63
+ }),
64
+ )
61
65
  })
62
66
  it('should generate unique session ID', () => {
63
- expect(core.activePlayback.options).toEqual(expect.objectContaining({
64
- dash: expect.objectContaining({
65
- cmcd: expect.objectContaining({
66
- sid: '123',
67
- })
68
- })
69
- }))
67
+ expect(core.containers[0].playback.options).toEqual(
68
+ expect.objectContaining({
69
+ dash: expect.objectContaining({
70
+ cmcd: expect.objectContaining({
71
+ sid: '123',
72
+ }),
73
+ }),
74
+ }),
75
+ )
70
76
  })
71
77
  it('should compute content ID from source URL', () => {
72
- expect(generateContentId).toHaveBeenCalledWith('https://123.mpd')
73
- expect(core.activePlayback.options).toEqual(expect.objectContaining({
74
- dash: expect.objectContaining({
75
- cmcd: expect.objectContaining({
76
- cid: 'deadbeef',
77
- })
78
- })
79
- }))
78
+ expect(core.containers[0].playback.options).toEqual(
79
+ expect.objectContaining({
80
+ dash: expect.objectContaining({
81
+ cmcd: expect.objectContaining({
82
+ cid: '/123.mpd',
83
+ }),
84
+ }),
85
+ }),
86
+ )
80
87
  })
81
88
  })
82
89
  describe('hls.js', () => {
83
90
  beforeEach(async () => {
84
- core.activeContainer.playback.name = 'hls'
85
- core.activeContainer.playback.options.src = 'https://123.m3u8'
91
+ core.containers[0].playback.name = 'hls'
86
92
  plugin = new CmcdConfig(core)
87
- await new Promise(resolve => setTimeout(resolve, 0))
88
- core.trigger(Events.CORE_ACTIVE_CONTAINER_CHANGED)
89
- await new Promise(resolve => setTimeout(resolve, 0))
93
+ core.trigger(Events.CORE_CONTAINERS_CREATED)
90
94
  })
91
95
  it('should update HLS.js CMCD settings', () => {
92
- expect(core.activePlayback.options).toEqual(expect.objectContaining({
93
- playback: expect.objectContaining({
94
- hlsjsConfig: expect.objectContaining({
95
- cmcd: expect.objectContaining({
96
- includeKeys: CMCD_KEYS,
97
- contentId: 'deadbeef',
98
- sessionId: '123',
99
- })
100
- })
101
- })
102
- }))
103
- expect(generateContentId).toHaveBeenCalledWith('https://123.m3u8')
96
+ expect(core.containers[0].playback.options).toEqual(
97
+ expect.objectContaining({
98
+ playback: expect.objectContaining({
99
+ hlsjsConfig: expect.objectContaining({
100
+ cmcd: expect.objectContaining({
101
+ includeKeys: CMCD_KEYS,
102
+ contentId: '/123.mpd',
103
+ sessionId: '123',
104
+ }),
105
+ }),
106
+ }),
107
+ }),
108
+ )
104
109
  })
105
110
  })
106
111
  })
@@ -109,54 +114,61 @@ describe('CmcdConfig', () => {
109
114
  beforeEach(async () => {
110
115
  core = createMockCore({
111
116
  cmcd: {
112
- contentId: (src: string) => new Promise(resolve => {
113
- const h = createHash('sha256')
114
- h.on('readable', () => {
115
- const data = h.read()
116
- if (data) {
117
- resolve(data.toString('hex'))
118
- }
119
- })
120
- h.update(Buffer.from('1$' + src))
121
- h.end()
122
- }),
123
- }
117
+ contentId:
118
+ 'e287ea99b57c09b7a185aaaf36e075f2c0b346ce90aeced72976b1732678a8c6',
119
+ },
120
+ sources: [
121
+ {
122
+ source: 'https://zulu.com/123.mpd',
123
+ mimeType: 'application/dash+xml',
124
+ },
125
+ ],
124
126
  })
125
- core.activePlayback.name = 'dash'
126
- core.activePlayback.options.src = 'https://123.mpd'
127
+ core.containers[0].playback.name = 'dash'
128
+ core.containers[0].playback.options.src = 'https://123.mpd'
127
129
  plugin = new CmcdConfig(core)
128
- core.trigger(Events.CORE_ACTIVE_CONTAINER_CHANGED)
129
- await new Promise(resolve => setTimeout(resolve, 0))
130
+ core.trigger(Events.CORE_CONTAINERS_CREATED)
131
+ await new Promise((resolve) => setTimeout(resolve, 0))
130
132
  })
131
133
  it('should use custom content ID', () => {
132
- expect(core.activePlayback.options).toEqual(expect.objectContaining({
133
- dash: expect.objectContaining({
134
- cmcd: expect.objectContaining({
135
- cid: 'e287ea99b57c09b7a185aaaf36e075f2c0b346ce90aeced72976b1732678a8c6',
136
- })
137
- })
138
- }))
134
+ expect(core.containers[0].playback.options).toEqual(
135
+ expect.objectContaining({
136
+ dash: expect.objectContaining({
137
+ cmcd: expect.objectContaining({
138
+ cid: 'e287ea99b57c09b7a185aaaf36e075f2c0b346ce90aeced72976b1732678a8c6',
139
+ }),
140
+ }),
141
+ }),
142
+ )
139
143
  })
140
144
  })
141
145
  describe('custom session ID', () => {
142
146
  beforeEach(async () => {
143
147
  core = createMockCore({
144
148
  cmcd: { sessionId: '456' },
149
+ sources: [
150
+ {
151
+ source: 'https://zulu.com/123.mpd',
152
+ mimeType: 'application/dash+xml',
153
+ },
154
+ ],
145
155
  })
146
- core.activePlayback.name = 'dash'
147
- core.activePlayback.options.src = 'https://123.mpd'
156
+ core.containers[0].playback.name = 'dash'
157
+ core.containers[0].playback.options.src = 'https://123.mpd'
148
158
  plugin = new CmcdConfig(core)
149
- core.trigger(Events.CORE_ACTIVE_CONTAINER_CHANGED)
150
- await new Promise(resolve => setTimeout(resolve, 0))
159
+ core.trigger(Events.CORE_CONTAINERS_CREATED)
160
+ await new Promise((resolve) => setTimeout(resolve, 0))
151
161
  })
152
162
  it('should use custom session ID', () => {
153
- expect(core.activePlayback.options).toEqual(expect.objectContaining({
154
- dash: expect.objectContaining({
155
- cmcd: expect.objectContaining({
156
- sid: '456',
157
- })
158
- })
159
- }))
163
+ expect(core.containers[0].playback.options).toEqual(
164
+ expect.objectContaining({
165
+ dash: expect.objectContaining({
166
+ cmcd: expect.objectContaining({
167
+ sid: '456',
168
+ }),
169
+ }),
170
+ }),
171
+ )
160
172
  })
161
173
  })
162
174
  })
@@ -1,13 +1,3 @@
1
1
  export function generateSessionId(): string {
2
2
  return window.crypto.randomUUID()
3
3
  }
4
-
5
- export function generateContentId(sourceUrl: string): Promise<string> {
6
- return window.crypto.subtle.digest('SHA-1', new TextEncoder().encode(sourceUrl))
7
- .then(buffer => {
8
- const hex = Array.from(new Uint8Array(buffer))
9
- .map(b => b.toString(16).padStart(2, '0'))
10
- .join('')
11
- return hex
12
- })
13
- }
@@ -531,6 +531,18 @@ export class MediaControl extends UICorePlugin {
531
531
  this.show()
532
532
  }
533
533
 
534
+ /**
535
+ *
536
+ * @returns Vertical space available to render something on top of the container.
537
+ * @remarks
538
+ * This takes into account the container height and excludes the height of the controls bar
539
+ */
540
+ getAvailableHeight() {
541
+ return (
542
+ this.core.$el.height() - this.$el.find('.media-control-layer').height()
543
+ )
544
+ }
545
+
534
546
  /**
535
547
  * Set the initial volume, which is preserved when playback is interrupted by an advertisement
536
548
  */
@@ -645,12 +657,12 @@ export class MediaControl extends UICorePlugin {
645
657
  }
646
658
 
647
659
  private mousemoveOnSeekBar(event: MouseEvent) {
648
- const offset = MediaControl.getPageX(event) -
649
- (this.$seekBarContainer.offset().left ?? 0) // TODO check if the result can be negative
650
- const hoverOffset =
651
- offset -
652
- (this.$seekBarHover.width() ?? 0) / 2
653
- const pos = offset ? Math.min(1, Math.max(offset / this.$seekBarContainer.width(), 0)) : 0
660
+ const offset =
661
+ MediaControl.getPageX(event) - (this.$seekBarContainer.offset().left ?? 0) // TODO check if the result can be negative
662
+ const hoverOffset = offset - (this.$seekBarHover.width() ?? 0) / 2
663
+ const pos = offset
664
+ ? Math.min(1, Math.max(offset / this.$seekBarContainer.width(), 0))
665
+ : 0
654
666
  if (this.settings.seekEnabled) {
655
667
  // TODO test that it works when the element does not exist
656
668
  this.$seekBarHover.css({ left: hoverOffset })
package/src/testUtils.ts CHANGED
@@ -13,6 +13,7 @@ export function createMockCore(
13
13
  $el: $(el),
14
14
  activePlayback: container.playback,
15
15
  activeContainer: container,
16
+ containers: [container],
16
17
  i18n: {
17
18
  t: vi.fn().mockImplementation((key: string) => key),
18
19
  },
@@ -125,6 +126,8 @@ export function createMockMediaControl(core: any) {
125
126
  // @ts-ignore
126
127
  mediaControl.container = core.activeContainer
127
128
  // @ts-ignore
129
+ mediaControl.getAvailableHeight = vi.fn().mockReturnValue(300)
130
+ // @ts-ignore
128
131
  mediaControl.toggleElement = vi.fn()
129
132
  vi.spyOn(mediaControl, 'trigger')
130
133
  core.$el.append(mediaControl.$el)