@gcorevideo/player 2.22.22 → 2.22.24

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 (56) hide show
  1. package/assets/clappr-nerd-stats/clappr-nerd-stats.scss +0 -3
  2. package/assets/subtitles/combobox.ejs +1 -1
  3. package/assets/subtitles/style.scss +0 -1
  4. package/dist/core.js +1 -1
  5. package/dist/index.css +1504 -1505
  6. package/dist/index.js +4367 -4332
  7. package/dist/plugins/index.css +641 -642
  8. package/dist/plugins/index.js +5408 -5376
  9. package/lib/index.plugins.d.ts +2 -2
  10. package/lib/index.plugins.d.ts.map +1 -1
  11. package/lib/index.plugins.js +2 -2
  12. package/lib/plugins/audio-selector/AudioTracks.d.ts +67 -0
  13. package/lib/plugins/audio-selector/AudioTracks.d.ts.map +1 -0
  14. package/lib/plugins/audio-selector/AudioTracks.js +181 -0
  15. package/lib/plugins/bottom-gear/BottomGear.d.ts +1 -1
  16. package/lib/plugins/bottom-gear/BottomGear.d.ts.map +1 -1
  17. package/lib/plugins/bottom-gear/BottomGear.js +13 -3
  18. package/lib/plugins/clappr-nerd-stats/NerdStats.d.ts +1 -1
  19. package/lib/plugins/clappr-nerd-stats/NerdStats.d.ts.map +1 -1
  20. package/lib/plugins/clappr-nerd-stats/NerdStats.js +11 -5
  21. package/lib/plugins/clappr-nerd-stats/speedtest/Speedtest.d.ts.map +1 -1
  22. package/lib/plugins/clappr-nerd-stats/speedtest/Speedtest.js +0 -1
  23. package/lib/plugins/clappr-nerd-stats/utils.d.ts.map +1 -1
  24. package/lib/plugins/clappr-nerd-stats/utils.js +0 -3
  25. package/lib/plugins/media-control/MediaControl.d.ts +2 -1
  26. package/lib/plugins/media-control/MediaControl.d.ts.map +1 -1
  27. package/lib/plugins/media-control/MediaControl.js +1 -0
  28. package/lib/plugins/skip-time/SkipTime.d.ts +2 -2
  29. package/lib/plugins/skip-time/SkipTime.d.ts.map +1 -1
  30. package/lib/plugins/skip-time/SkipTime.js +6 -5
  31. package/lib/plugins/subtitles/ClosedCaptions.d.ts +3 -3
  32. package/lib/plugins/subtitles/ClosedCaptions.d.ts.map +1 -1
  33. package/lib/plugins/subtitles/ClosedCaptions.js +34 -19
  34. package/lib/testUtils.d.ts.map +1 -1
  35. package/lib/testUtils.js +1 -0
  36. package/package.json +1 -1
  37. package/src/index.plugins.ts +2 -2
  38. package/src/plugins/audio-selector/{AudioSelector.ts → AudioTracks.ts} +16 -8
  39. package/src/plugins/audio-selector/__tests__/{AudioSelector.test.ts → AudioTracks.test.ts} +42 -25
  40. package/src/plugins/audio-selector/__tests__/__snapshots__/AudioSelector.test.ts.snap +66 -0
  41. package/src/plugins/audio-selector/__tests__/__snapshots__/AudioTracks.test.ts.snap +67 -0
  42. package/src/plugins/bottom-gear/BottomGear.ts +17 -3
  43. package/src/plugins/bottom-gear/__tests__/BottomGear.test.ts +22 -1
  44. package/src/plugins/clappr-nerd-stats/NerdStats.ts +12 -6
  45. package/src/plugins/clappr-nerd-stats/speedtest/Speedtest.ts +0 -1
  46. package/src/plugins/clappr-nerd-stats/utils.ts +0 -3
  47. package/src/plugins/media-control/MediaControl.ts +1 -0
  48. package/src/plugins/skip-time/SkipTime.ts +45 -38
  49. package/src/plugins/subtitles/ClosedCaptions.ts +40 -23
  50. package/src/plugins/subtitles/__tests__/ClosedCaptions.test.ts +51 -13
  51. package/src/plugins/subtitles/__tests__/__snapshots__/ClosedCaptions.test.ts.snap +4 -4
  52. package/src/testUtils.ts +1 -0
  53. package/tsconfig.tsbuildinfo +1 -1
  54. package/assets/subtitles/combobox copy.ejs +0 -16
  55. /package/assets/{audio-selector → audio-tracks}/style.scss +0 -0
  56. /package/assets/{audio-selector/track-selector.ejs → audio-tracks/template.ejs} +0 -0
@@ -8,6 +8,7 @@ import subtitlesOnIcon from '../../../assets/icons/new/subtitles-on.svg';
8
8
  import comboboxHTML from '../../../assets/subtitles/combobox.ejs';
9
9
  import stringHTML from '../../../assets/subtitles/string.ejs';
10
10
  import { isFullscreen } from '../utils/fullscreen.js';
11
+ import { ExtendedEvents } from '../media-control/MediaControl.js';
11
12
  const VERSION = '2.19.14';
12
13
  const LOCAL_STORAGE_CC_ID = 'gplayer.plugins.cc.selected';
13
14
  const T = 'plugins.cc';
@@ -40,7 +41,7 @@ const T = 'plugins.cc';
40
41
  */
41
42
  export class ClosedCaptions extends UICorePlugin {
42
43
  isPreselectedApplied = false;
43
- isShowing = false;
44
+ active = false;
44
45
  track = null;
45
46
  tracks = [];
46
47
  $line = null;
@@ -77,12 +78,14 @@ export class ClosedCaptions extends UICorePlugin {
77
78
  */
78
79
  get events() {
79
80
  return {
80
- 'click [data-cc-select]': 'onItemSelect',
81
- 'click [data-cc-button]': 'toggleMenu',
81
+ 'click #cc-select li a': 'onItemSelect',
82
+ 'click #cc-button': 'toggleMenu',
82
83
  };
83
84
  }
84
85
  get preselectedLanguage() {
85
- return this.core.options.cc?.language ?? this.core.options.subtitles?.language ?? '';
86
+ return (this.core.options.cc?.language ??
87
+ this.core.options.subtitles?.language ??
88
+ '');
86
89
  }
87
90
  /**
88
91
  * @internal
@@ -96,8 +99,15 @@ export class ClosedCaptions extends UICorePlugin {
96
99
  trace(`${T} onCoreReady`);
97
100
  const mediaControl = this.core.getPlugin('media_control');
98
101
  assert(mediaControl, 'media_control plugin is required');
99
- this.listenTo(mediaControl, Events.MEDIACONTROL_RENDERED, this.render);
100
- this.listenTo(mediaControl, Events.MEDIACONTROL_HIDE, this.hideMenu);
102
+ this.listenTo(mediaControl, Events.MEDIACONTROL_RENDERED, this.render); // TODO mount to media control
103
+ this.listenTo(mediaControl, Events.MEDIACONTROL_HIDE, () => {
104
+ this.hideMenu();
105
+ });
106
+ this.listenTo(mediaControl, ExtendedEvents.MEDIACONTROL_MENU_COLLAPSE, (from) => {
107
+ if (from !== this.name) {
108
+ this.hideMenu();
109
+ }
110
+ });
101
111
  }
102
112
  onContainerChanged() {
103
113
  trace(`${T} onContainerChanged`);
@@ -164,7 +174,7 @@ export class ClosedCaptions extends UICorePlugin {
164
174
  }
165
175
  }
166
176
  onStartAd() {
167
- if (this.isShowing && this.core.activeContainer) {
177
+ if (this.active && this.core.activeContainer) {
168
178
  this.hide();
169
179
  this.listenTo(this.core.activeContainer, 'container:advertisement:finish', this.onFinishAd);
170
180
  }
@@ -180,7 +190,7 @@ export class ClosedCaptions extends UICorePlugin {
180
190
  this.track &&
181
191
  this.track.track.mode &&
182
192
  Browser.isiOS &&
183
- this.isShowing;
193
+ this.active;
184
194
  if (shouldShow) {
185
195
  this.show();
186
196
  }
@@ -195,7 +205,7 @@ export class ClosedCaptions extends UICorePlugin {
195
205
  * Hides the subtitles menu and the subtitles.
196
206
  */
197
207
  hide() {
198
- this.isShowing = false;
208
+ this.active = false;
199
209
  this.renderIcon();
200
210
  this.$line.hide();
201
211
  if (this.tracks) {
@@ -208,7 +218,7 @@ export class ClosedCaptions extends UICorePlugin {
208
218
  * Shows the subtitles menu and the subtitles.
209
219
  */
210
220
  show() {
211
- this.isShowing = true;
221
+ this.active = true;
212
222
  this.renderIcon();
213
223
  if (this.core.activeContainer &&
214
224
  isFullscreen(this.core.activeContainer.el) &&
@@ -243,7 +253,8 @@ export class ClosedCaptions extends UICorePlugin {
243
253
  return this;
244
254
  }
245
255
  const mediaControl = this.core.getPlugin('media_control');
246
- this.$el.html(ClosedCaptions.template({ tracks: this.tracks }));
256
+ this.$el.html(ClosedCaptions.template({ tracks: this.tracks, i18n: this.core.i18n }));
257
+ this.$el.find('#cc-select').hide();
247
258
  this.core.activeContainer.$el.find('#cc-line').remove();
248
259
  this.$line = $(ClosedCaptions.templateString());
249
260
  this.resizeFont();
@@ -259,7 +270,6 @@ export class ClosedCaptions extends UICorePlugin {
259
270
  selectItem(item) {
260
271
  this.clearSubtitleText();
261
272
  this.track = item;
262
- this.hideMenu();
263
273
  this.updateSelection();
264
274
  }
265
275
  onItemSelect(event) {
@@ -267,6 +277,7 @@ export class ClosedCaptions extends UICorePlugin {
267
277
  trace(`${T} onItemSelect`, { id });
268
278
  localStorage.setItem(LOCAL_STORAGE_CC_ID, id);
269
279
  this.selectItem(this.findById(Number(id)));
280
+ this.hideMenu();
270
281
  return false;
271
282
  }
272
283
  applyPreselectedSubtitles() {
@@ -281,18 +292,22 @@ export class ClosedCaptions extends UICorePlugin {
281
292
  }
282
293
  }
283
294
  hideMenu() {
284
- ;
285
- this.$('[data-cc] ul').hide();
295
+ trace(`${T} hideMenu`);
296
+ this.$el.find('#cc-select').hide();
286
297
  }
287
298
  toggleMenu() {
288
- trace(`${T} toggleMenu`);
289
- this.$('[data-cc] ul').toggle();
299
+ trace(`${T} toggleMenu`, { display: this.$el.find('#cc-select').css('display') });
300
+ this.core
301
+ .getPlugin('media_control')
302
+ .trigger(ExtendedEvents.MEDIACONTROL_MENU_COLLAPSE, this.name);
303
+ this.$el.find('#cc-select').toggle();
304
+ // TODO hold state, add aria-expanded to the button, add active state to the button
290
305
  }
291
306
  itemElement(id) {
292
- return this.$(`ul li a[data-cc-select="${id}"]`).parent();
307
+ return this.$el.find(`#cc-select li a[data-cc-select="${id}"]`).parent();
293
308
  }
294
309
  allItemElements() {
295
- return this.$('[data-cc] li');
310
+ return this.$('#cc-select li');
296
311
  }
297
312
  selectSubtitles() {
298
313
  const trackId = this.track ? this.track.id : -1;
@@ -342,7 +357,7 @@ export class ClosedCaptions extends UICorePlugin {
342
357
  .addClass('gcore-skin-active');
343
358
  }
344
359
  renderIcon() {
345
- const icon = this.isShowing ? subtitlesOnIcon : subtitlesOffIcon;
360
+ const icon = this.active ? subtitlesOnIcon : subtitlesOffIcon;
346
361
  this.$el.find('span.cc-text').html(icon);
347
362
  }
348
363
  }
@@ -1 +1 @@
1
- {"version":3,"file":"testUtils.d.ts","sourceRoot":"","sources":["../src/testUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,YAAY,EAAE,MAAM,cAAc,CAAA;AACxD,OAAO,MAAM,MAAM,eAAe,CAAA;AAElC;;;;GAIG;AACH,qBAAa,aAAc,SAAQ,MAAM;IAErC,SAAS,CAAC,OAAO,EAAE,GAAG;IACtB,QAAQ,CAAC,IAAI,EAAE,GAAG;IAClB,SAAS,CAAC,WAAW,CAAC,EAAE,GAAG;gBAFjB,OAAO,EAAE,GAAG,EACb,IAAI,EAAE,GAAG,EACR,WAAW,CAAC,EAAE,GAAG,YAAA;IAK7B,IAAI,IAAI,WAEP;IAED,OAAO;IAEP,IAAI;IAEJ,KAAK;IAEL,IAAI;IAEJ,OAAO;IAEP,IAAI;IAEJ,cAAc;IAEd,WAAW;IAIX,QAAQ;IAER,OAAO;IAEP,eAAe;IAIf,kBAAkB;IAIlB,cAAc;IAId,qBAAqB;IAIrB,IAAI;IAEJ,MAAM;IAEN,MAAM;IAEN,SAAS;IAET,eAAe;IAIf,WAAW;IAIX,QAAQ;IAIR,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE;CAGtC;AAED,wBAAgB,cAAc,CAC5B,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACrC,SAAS,GAAE,GAAkC;;;;;;;;;;;;;;;;EAqB9C;AAED,wBAAgB,gBAAgB;;;EAK/B;AAED,wBAAgB,mBAAmB;;;;;;EAKlC;AAED,wBAAgB,kBAAkB,CAAC,IAAI,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkC/C;AAED,wBAAgB,mBAAmB,CACjC,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACrC,QAAQ,GAAE,GAA0B;;;;;;;;;;;;;;;EAoBrC;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,GAAG,gBAc/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,EAAe,YAAY,EAAE,MAAM,cAAc,CAAA;AACxD,OAAO,MAAM,MAAM,eAAe,CAAA;AAElC;;;;GAIG;AACH,qBAAa,aAAc,SAAQ,MAAM;IAErC,SAAS,CAAC,OAAO,EAAE,GAAG;IACtB,QAAQ,CAAC,IAAI,EAAE,GAAG;IAClB,SAAS,CAAC,WAAW,CAAC,EAAE,GAAG;gBAFjB,OAAO,EAAE,GAAG,EACb,IAAI,EAAE,GAAG,EACR,WAAW,CAAC,EAAE,GAAG,YAAA;IAK7B,IAAI,IAAI,WAEP;IAED,OAAO;IAEP,IAAI;IAEJ,KAAK;IAEL,IAAI;IAEJ,OAAO;IAEP,IAAI;IAEJ,cAAc;IAEd,WAAW;IAIX,QAAQ;IAER,OAAO;IAEP,eAAe;IAIf,kBAAkB;IAIlB,cAAc;IAId,qBAAqB;IAIrB,IAAI;IAEJ,MAAM;IAEN,MAAM;IAEN,SAAS;IAET,eAAe;IAIf,WAAW;IAIX,QAAQ;IAIR,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE;CAGtC;AAED,wBAAgB,cAAc,CAC5B,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACrC,SAAS,GAAE,GAAkC;;;;;;;;;;;;;;;;EAqB9C;AAED,wBAAgB,gBAAgB;;;EAK/B;AAED,wBAAgB,mBAAmB;;;;;;EAKlC;AAED,wBAAgB,kBAAkB,CAAC,IAAI,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkC/C;AAED,wBAAgB,mBAAmB,CACjC,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACrC,QAAQ,GAAE,GAA0B;;;;;;;;;;;;;;;EAoBrC;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,GAAG,gBAe/C;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,GAAG,OAe7C"}
package/lib/testUtils.js CHANGED
@@ -159,6 +159,7 @@ export function createMockMediaControl(core) {
159
159
  mediaControl.mount = vi.fn();
160
160
  // @ts-ignore
161
161
  mediaControl.toggleElement = vi.fn();
162
+ vi.spyOn(mediaControl, 'trigger');
162
163
  return mediaControl;
163
164
  }
164
165
  export function createMockBottomGear(core) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gcorevideo/player",
3
- "version": "2.22.22",
3
+ "version": "2.22.24",
4
4
  "description": "Gcore JavaScript video player",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -1,7 +1,7 @@
1
1
  import '../assets/style/main.scss';
2
2
 
3
- export * from "./plugins/audio-selector/AudioSelector.js";
4
- export { AudioTracks as AudioSelector } from "./plugins/audio-selector/AudioSelector.js";
3
+ export * from "./plugins/audio-selector/AudioTracks.js";
4
+ export { AudioTracks as AudioSelector } from "./plugins/audio-selector/AudioTracks.js";
5
5
  export * from "./plugins/big-mute-button/BigMuteButton.js";
6
6
  export * from "./plugins/bottom-gear/BottomGear.js";
7
7
  export * from "./plugins/clappr-stats/ClapprStats.js";
@@ -4,16 +4,16 @@ import assert from 'assert'
4
4
 
5
5
  import { CLAPPR_VERSION } from '../../build.js'
6
6
 
7
- import pluginHtml from '../../../assets/audio-selector/track-selector.ejs'
8
- import '../../../assets/audio-selector/style.scss'
7
+ import pluginHtml from '../../../assets/audio-tracks/template.ejs'
8
+ import '../../../assets/audio-tracks/style.scss'
9
9
  import audioArrow from '../../../assets/icons/old/quality-arrow.svg'
10
10
  import { ZeptoResult } from '../../types.js'
11
- import { MediaControl } from '../media-control/MediaControl.js'
12
- // import { trace } from '@gcorevideo/utils'
11
+ import { ExtendedEvents, MediaControl } from '../media-control/MediaControl.js'
12
+ import { trace } from '@gcorevideo/utils'
13
13
 
14
14
  const VERSION: string = '2.22.4'
15
15
 
16
- // const T = 'plugins.audiotracks'
16
+ const T = 'plugins.audiotracks'
17
17
 
18
18
  /**
19
19
  * `PLUGIN` that makes possible to switch audio tracks via the media control UI.
@@ -34,7 +34,7 @@ export class AudioTracks extends UICorePlugin {
34
34
  * @internal
35
35
  */
36
36
  get name() {
37
- return 'audio_selector' // TODO rename to audiotracks
37
+ return 'audio_tracks'
38
38
  }
39
39
 
40
40
  /**
@@ -68,7 +68,7 @@ export class AudioTracks extends UICorePlugin {
68
68
  override get events() {
69
69
  return {
70
70
  'click [data-audiotracks-select]': 'onTrackSelect',
71
- 'click #audiotracks-button': 'toggleContextMenu',
71
+ 'click #audiotracks-button': 'toggleMenu',
72
72
  }
73
73
  }
74
74
 
@@ -91,6 +91,11 @@ export class AudioTracks extends UICorePlugin {
91
91
  mediaControl.mount('audiotracks', this.$el)
92
92
  })
93
93
  this.listenTo(mediaControl, Events.MEDIACONTROL_HIDE, this.hideMenu)
94
+ this.listenTo(mediaControl, ExtendedEvents.MEDIACONTROL_MENU_COLLAPSE, (from: string) => {
95
+ if (from !== this.name) {
96
+ this.hideMenu()
97
+ }
98
+ })
94
99
  }
95
100
 
96
101
  private onActiveContainerChanged() {
@@ -162,10 +167,13 @@ export class AudioTracks extends UICorePlugin {
162
167
  }
163
168
 
164
169
  private hideMenu() {
170
+ trace(`${T} hideMenu`)
165
171
  this.$el.find('#audiotracks-select').addClass('hidden')
172
+ this.$el.find('#audiotracks-button').attr('aria-expanded', 'false')
166
173
  }
167
174
 
168
- private toggleContextMenu() {
175
+ private toggleMenu() {
176
+ this.core.getPlugin('media_control').trigger(ExtendedEvents.MEDIACONTROL_MENU_COLLAPSE, this.name)
169
177
  this.$el.find('#audiotracks-select').toggleClass('hidden') // TODO use plain CSS display: none
170
178
  const open = !this.$el.find('#audiotracks-select').hasClass('hidden') // TODO hold state
171
179
  this.$el.find('#audiotracks-button').attr('aria-expanded', open)
@@ -1,23 +1,23 @@
1
1
  import { beforeEach, describe, expect, it, vi } from 'vitest'
2
2
  import { Events } from '@clappr/core'
3
-
4
- import { AudioTracks } from '../AudioSelector'
3
+ import { ExtendedEvents } from '../../media-control/MediaControl'
4
+ import { AudioTracks } from '../AudioTracks'
5
5
 
6
6
  import { createMockCore, createMockMediaControl } from '../../../testUtils'
7
7
  // import { LogTracer, Logger, setTracer } from '@gcorevideo/utils'
8
8
 
9
9
  // Logger.enable('*')
10
- // setTracer(new LogTracer('AudioSelector.test'))
10
+ // setTracer(new LogTracer('AudioTracks.test'))
11
11
 
12
12
  const TRACKS = [
13
13
  { id: '1', label: 'English', language: 'en', track: {} },
14
14
  { id: '2', label: 'Spanish', language: 'es', track: {} },
15
15
  ]
16
16
 
17
- describe('AudioSelector', () => {
17
+ describe('AudioTracks', () => {
18
18
  let core: any
19
19
  let mediaControl: any
20
- let audioSelector: AudioTracks
20
+ let audioTracks: AudioTracks
21
21
  beforeEach(() => {
22
22
  core = createMockCore()
23
23
  mediaControl = createMockMediaControl(core)
@@ -25,7 +25,7 @@ describe('AudioSelector', () => {
25
25
  if (name === 'media_control') return mediaControl
26
26
  return null
27
27
  })
28
- audioSelector = new AudioTracks(core)
28
+ audioTracks = new AudioTracks(core)
29
29
  core.emit(Events.CORE_READY)
30
30
  core.emit(Events.CORE_ACTIVE_CONTAINER_CHANGED, core.activeContainer)
31
31
  })
@@ -47,7 +47,7 @@ describe('AudioSelector', () => {
47
47
  it('should attach to the media control', () => {
48
48
  expect(mediaControl.mount).toHaveBeenCalledWith(
49
49
  'audiotracks',
50
- audioSelector.$el,
50
+ audioTracks.$el,
51
51
  )
52
52
  })
53
53
  })
@@ -56,31 +56,37 @@ describe('AudioSelector', () => {
56
56
  emitTracksAvailable(core, TRACKS)
57
57
  })
58
58
  it('should render button', () => {
59
- expect(audioSelector.$el.find('#audiotracks-button').length).toBe(1)
59
+ expect(audioTracks.$el.find('#audiotracks-button').length).toBe(1)
60
60
  })
61
61
  it('should render menu hidden', () => {
62
- expect(audioSelector.el.innerHTML).toMatchSnapshot()
62
+ expect(audioTracks.el.innerHTML).toMatchSnapshot()
63
63
  expect(
64
- audioSelector.$el.find('#audiotracks-select').hasClass('hidden'),
64
+ audioTracks.$el.find('#audiotracks-select').hasClass('hidden'),
65
65
  ).toBe(true)
66
- const trackItems = audioSelector.$el.find('#audiotracks-select li')
66
+ const trackItems = audioTracks.$el.find('#audiotracks-select li')
67
67
  expect(trackItems.length).toBe(2)
68
68
  expect(trackItems.eq(0).text().trim()).toBe('English')
69
69
  expect(trackItems.eq(1).text().trim()).toBe('Spanish')
70
70
  })
71
71
  describe('when button is clicked', () => {
72
72
  beforeEach(() => {
73
- audioSelector.$el.find('#audiotracks-button').click()
73
+ audioTracks.$el.find('#audiotracks-button').click()
74
74
  })
75
75
  it('should show menu', () => {
76
- expect(audioSelector.$el.html()).toMatchSnapshot()
76
+ expect(audioTracks.$el.html()).toMatchSnapshot()
77
77
  expect(
78
- audioSelector.$el.find('#audiotracks-select').hasClass('hidden'),
78
+ audioTracks.$el.find('#audiotracks-select').hasClass('hidden'),
79
79
  ).toBe(false)
80
80
  })
81
+ it('should collapse all other menus', () => {
82
+ expect(mediaControl.trigger).toHaveBeenCalledWith(
83
+ ExtendedEvents.MEDIACONTROL_MENU_COLLAPSE,
84
+ 'audio_tracks',
85
+ )
86
+ })
81
87
  describe('when audio track is selected', () => {
82
88
  beforeEach(() => {
83
- audioSelector.$el
89
+ audioTracks.$el
84
90
  .find('#audiotracks-select [data-audiotracks-select="2"]')
85
91
  .click()
86
92
  })
@@ -90,14 +96,15 @@ describe('AudioSelector', () => {
90
96
  )
91
97
  })
92
98
  it('should hide the menu', () => {
93
- expect(audioSelector.$el.html()).toMatchSnapshot()
99
+ expect(audioTracks.$el.html()).toMatchSnapshot()
94
100
  expect(
95
- audioSelector.$el.find('#audiotracks-select').hasClass('hidden'),
101
+ audioTracks.$el.find('#audiotracks-select').hasClass('hidden'),
96
102
  ).toBe(true)
103
+ expect(audioTracks.$el.find('#audiotracks-button').attr('aria-expanded')).toBe('false')
97
104
  })
98
105
  it('should add changing class to the button', () => {
99
106
  expect(
100
- audioSelector.$el.find('#audiotracks-button').hasClass('changing'),
107
+ audioTracks.$el.find('#audiotracks-button').hasClass('changing'),
101
108
  ).toBe(true)
102
109
  })
103
110
  describe('when current audio track changes', () => {
@@ -115,14 +122,14 @@ describe('AudioSelector', () => {
115
122
  })
116
123
  it('should update button class', () => {
117
124
  expect(
118
- audioSelector.$el
125
+ audioTracks.$el
119
126
  .find('#audiotracks-button')
120
127
  .hasClass('changing'),
121
128
  ).toBe(false)
122
129
  })
123
130
  it('should update button label', () => {
124
131
  expect(
125
- audioSelector.$el
132
+ audioTracks.$el
126
133
  .find('#audiotracks-button')
127
134
  .text()
128
135
  .replace(/\/assets.*\.svg/g, '')
@@ -130,7 +137,7 @@ describe('AudioSelector', () => {
130
137
  ).toBe('Spanish')
131
138
  })
132
139
  it('should highlight the selected menu item', () => {
133
- const selectedItem = audioSelector.$el.find(
140
+ const selectedItem = audioTracks.$el.find(
134
141
  '#audiotracks-select .current',
135
142
  )
136
143
  expect(selectedItem.text().trim()).toBe('Spanish')
@@ -142,10 +149,10 @@ describe('AudioSelector', () => {
142
149
  })
143
150
  it('should unhighlight any previously highlighted menu item', () => {
144
151
  expect(
145
- audioSelector.$el.find('#audiotracks-select li.current').length,
152
+ audioTracks.$el.find('#audiotracks-select li.current').length,
146
153
  ).toBe(1)
147
154
  expect(
148
- audioSelector.$el.find(
155
+ audioTracks.$el.find(
149
156
  '#audiotracks-select a.gcore-skin-active[data-audiotracks-select]',
150
157
  ).length,
151
158
  ).toBe(1)
@@ -153,11 +160,21 @@ describe('AudioSelector', () => {
153
160
  })
154
161
  })
155
162
  })
163
+ describe('when button is clicked twice', () => {
164
+ beforeEach(() => {
165
+ audioTracks.$el.find('#audiotracks-button').click()
166
+ audioTracks.$el.find('#audiotracks-button').click()
167
+ })
168
+ it('should collapse the menu', () => {
169
+ expect(audioTracks.$el.find('#audiotracks-select').hasClass('hidden')).toBe(true)
170
+ expect(audioTracks.$el.find('#audiotracks-button').attr('aria-expanded')).toBe('false')
171
+ })
172
+ })
156
173
  })
157
174
  describe('when audio tracks are not available', () => {
158
175
  it('should not render the button', () => {
159
- expect(audioSelector.$el.find('#audiotracks-button').length).toBe(0)
160
- expect(audioSelector.$el.find('#audiotracks-select').length).toBe(0)
176
+ expect(audioTracks.$el.find('#audiotracks-button').length).toBe(0)
177
+ expect(audioTracks.$el.find('#audiotracks-select').length).toBe(0)
161
178
  })
162
179
  })
163
180
  })
@@ -65,3 +65,69 @@ exports[`AudioSelector > given that audio tracks are available > when button is
65
65
  </ul>
66
66
  "
67
67
  `;
68
+
69
+ exports[`AudioTracks > given that audio tracks are available > should render menu hidden 1`] = `
70
+ "<button data-audiotracks-button="" class="gcore-skin-button-color" id="audiotracks-button" aria-haspopup="menu" aria-expanded="false">
71
+ <span class="audio-text"></span> <span class="audio-arrow">/assets/icons/old/quality-arrow.svg</span>
72
+ </button>
73
+ <ul class="gcore-skin-bg-color menu hidden" id="audiotracks-select" role="menu">
74
+
75
+ <li class="">
76
+ <a href="#" class="gcore-skin-text-color" data-audiotracks-select="1" role="menuitemradio" aria-checked="false">
77
+ English
78
+ </a>
79
+ </li>
80
+
81
+ <li class="">
82
+ <a href="#" class="gcore-skin-text-color" data-audiotracks-select="2" role="menuitemradio" aria-checked="false">
83
+ Spanish
84
+ </a>
85
+ </li>
86
+
87
+ </ul>
88
+ "
89
+ `;
90
+
91
+ exports[`AudioTracks > given that audio tracks are available > when button is clicked > should show menu 1`] = `
92
+ "<button data-audiotracks-button="" class="gcore-skin-button-color" id="audiotracks-button" aria-haspopup="menu" aria-expanded="true">
93
+ <span class="audio-text"></span> <span class="audio-arrow">/assets/icons/old/quality-arrow.svg</span>
94
+ </button>
95
+ <ul class="gcore-skin-bg-color menu" id="audiotracks-select" role="menu">
96
+
97
+ <li class="">
98
+ <a href="#" class="gcore-skin-text-color" data-audiotracks-select="1" role="menuitemradio" aria-checked="false">
99
+ English
100
+ </a>
101
+ </li>
102
+
103
+ <li class="">
104
+ <a href="#" class="gcore-skin-text-color" data-audiotracks-select="2" role="menuitemradio" aria-checked="false">
105
+ Spanish
106
+ </a>
107
+ </li>
108
+
109
+ </ul>
110
+ "
111
+ `;
112
+
113
+ exports[`AudioTracks > given that audio tracks are available > when button is clicked > when audio track is selected > should hide the menu 1`] = `
114
+ "<button data-audiotracks-button="" class="gcore-skin-button-color changing" id="audiotracks-button" aria-haspopup="menu" aria-expanded="true">
115
+ <span class="audio-text"></span> <span class="audio-arrow">/assets/icons/old/quality-arrow.svg</span>
116
+ </button>
117
+ <ul class="gcore-skin-bg-color menu hidden" id="audiotracks-select" role="menu">
118
+
119
+ <li class="">
120
+ <a href="#" class="gcore-skin-text-color" data-audiotracks-select="1" role="menuitemradio" aria-checked="false">
121
+ English
122
+ </a>
123
+ </li>
124
+
125
+ <li class="">
126
+ <a href="#" class="gcore-skin-text-color" data-audiotracks-select="2" role="menuitemradio" aria-checked="false">
127
+ Spanish
128
+ </a>
129
+ </li>
130
+
131
+ </ul>
132
+ "
133
+ `;
@@ -0,0 +1,67 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`AudioTracks > given that audio tracks are available > should render menu hidden 1`] = `
4
+ "<button data-audiotracks-button="" class="gcore-skin-button-color" id="audiotracks-button" aria-haspopup="menu" aria-expanded="false">
5
+ <span class="audio-text"></span> <span class="audio-arrow">/assets/icons/old/quality-arrow.svg</span>
6
+ </button>
7
+ <ul class="gcore-skin-bg-color menu hidden" id="audiotracks-select" role="menu">
8
+
9
+ <li class="">
10
+ <a href="#" class="gcore-skin-text-color" data-audiotracks-select="1" role="menuitemradio" aria-checked="false">
11
+ English
12
+ </a>
13
+ </li>
14
+
15
+ <li class="">
16
+ <a href="#" class="gcore-skin-text-color" data-audiotracks-select="2" role="menuitemradio" aria-checked="false">
17
+ Spanish
18
+ </a>
19
+ </li>
20
+
21
+ </ul>
22
+ "
23
+ `;
24
+
25
+ exports[`AudioTracks > given that audio tracks are available > when button is clicked > should show menu 1`] = `
26
+ "<button data-audiotracks-button="" class="gcore-skin-button-color" id="audiotracks-button" aria-haspopup="menu" aria-expanded="true">
27
+ <span class="audio-text"></span> <span class="audio-arrow">/assets/icons/old/quality-arrow.svg</span>
28
+ </button>
29
+ <ul class="gcore-skin-bg-color menu" id="audiotracks-select" role="menu">
30
+
31
+ <li class="">
32
+ <a href="#" class="gcore-skin-text-color" data-audiotracks-select="1" role="menuitemradio" aria-checked="false">
33
+ English
34
+ </a>
35
+ </li>
36
+
37
+ <li class="">
38
+ <a href="#" class="gcore-skin-text-color" data-audiotracks-select="2" role="menuitemradio" aria-checked="false">
39
+ Spanish
40
+ </a>
41
+ </li>
42
+
43
+ </ul>
44
+ "
45
+ `;
46
+
47
+ exports[`AudioTracks > given that audio tracks are available > when button is clicked > when audio track is selected > should hide the menu 1`] = `
48
+ "<button data-audiotracks-button="" class="gcore-skin-button-color changing" id="audiotracks-button" aria-haspopup="menu" aria-expanded="false">
49
+ <span class="audio-text"></span> <span class="audio-arrow">/assets/icons/old/quality-arrow.svg</span>
50
+ </button>
51
+ <ul class="gcore-skin-bg-color menu hidden" id="audiotracks-select" role="menu">
52
+
53
+ <li class="">
54
+ <a href="#" class="gcore-skin-text-color" data-audiotracks-select="1" role="menuitemradio" aria-checked="false">
55
+ English
56
+ </a>
57
+ </li>
58
+
59
+ <li class="">
60
+ <a href="#" class="gcore-skin-text-color" data-audiotracks-select="2" role="menuitemradio" aria-checked="false">
61
+ Spanish
62
+ </a>
63
+ </li>
64
+
65
+ </ul>
66
+ "
67
+ `;
@@ -10,6 +10,7 @@ import '../../../assets/bottom-gear/gear-sub-menu.scss'
10
10
  import gearIcon from '../../../assets/icons/new/gear.svg'
11
11
  import gearHdIcon from '../../../assets/icons/new/gear-hd.svg'
12
12
  import { ZeptoResult } from '../../types.js'
13
+ import { ExtendedEvents } from '../media-control/MediaControl.js'
13
14
 
14
15
  const VERSION = '2.19.12'
15
16
 
@@ -97,7 +98,7 @@ export enum GearEvents {
97
98
  * ```
98
99
  */
99
100
  export class BottomGear extends UICorePlugin {
100
- private isHd = false
101
+ private hd = false
101
102
 
102
103
  /**
103
104
  * @internal
@@ -215,7 +216,7 @@ export class BottomGear extends UICorePlugin {
215
216
 
216
217
  private highDefinitionUpdate(isHd: boolean) {
217
218
  trace(`${T} highDefinitionUpdate`, { isHd })
218
- this.isHd = isHd
219
+ this.hd = isHd
219
220
  this.$el.find('.gear-icon').html(isHd ? gearHdIcon : gearIcon)
220
221
  }
221
222
 
@@ -228,7 +229,7 @@ export class BottomGear extends UICorePlugin {
228
229
  if (!mediaControl) {
229
230
  return this // TODO test
230
231
  }
231
- const icon = this.isHd ? gearHdIcon : gearIcon
232
+ const icon = this.hd ? gearHdIcon : gearIcon
232
233
  this.$el
233
234
  .html(BottomGear.template({ icon }))
234
235
  .find('#gear-sub-menu-wrapper')
@@ -254,10 +255,14 @@ export class BottomGear extends UICorePlugin {
254
255
  }
255
256
 
256
257
  private toggleGearMenu() {
258
+ this.core
259
+ .getPlugin('media_control')
260
+ .trigger(ExtendedEvents.MEDIACONTROL_MENU_COLLAPSE, this.name)
257
261
  this.$el.find('#gear-options-wrapper').toggle()
258
262
  }
259
263
 
260
264
  private hide() {
265
+ trace(`${T} hide`)
261
266
  this.$el.find('#gear-options-wrapper').hide()
262
267
  }
263
268
 
@@ -271,6 +276,15 @@ export class BottomGear extends UICorePlugin {
271
276
  this.onMediaControlRendered,
272
277
  )
273
278
  this.listenTo(mediaControl, ClapprEvents.MEDIACONTROL_HIDE, this.hide)
279
+ this.listenTo(
280
+ mediaControl,
281
+ ExtendedEvents.MEDIACONTROL_MENU_COLLAPSE,
282
+ (from: string) => {
283
+ if (from !== this.name) {
284
+ this.hide()
285
+ }
286
+ },
287
+ )
274
288
  }
275
289
 
276
290
  private onMediaControlRendered() {
@@ -3,6 +3,7 @@ import { MockedFunction, beforeEach, describe, expect, it, vi } from 'vitest'
3
3
  import { BottomGear, GearEvents } from '../BottomGear'
4
4
  import { createMockCore, createMockMediaControl } from '../../../testUtils'
5
5
  import { Events } from '@clappr/core'
6
+ import { ExtendedEvents } from '../../media-control/MediaControl'
6
7
 
7
8
  describe('BottomGear', () => {
8
9
  let mediaControl: any
@@ -56,10 +57,30 @@ describe('BottomGear', () => {
56
57
  beforeEach(() => {
57
58
  bottomGear.$el.find('#gear-button').click()
58
59
  })
59
- it('should toggle the gear menu', () => {
60
+ it('should open the gear menu', () => {
60
61
  expect(
61
62
  bottomGear.$el.find('#gear-options-wrapper').css('display'),
62
63
  ).not.toBe('none')
63
64
  })
65
+ it('should trigger media control menu collapse', () => {
66
+ expect(mediaControl.trigger).toHaveBeenCalledWith(
67
+ ExtendedEvents.MEDIACONTROL_MENU_COLLAPSE,
68
+ 'bottom_gear',
69
+ )
70
+ })
71
+ })
72
+ describe('when clicked twice', () => {
73
+ beforeEach(() => {
74
+ console.log('display:%s', bottomGear.$el.find('#gear-options-wrapper').css('display'))
75
+ bottomGear.$el.find('#gear-button').click()
76
+ console.log('display:%s', bottomGear.$el.find('#gear-options-wrapper').css('display'))
77
+ bottomGear.$el.find('#gear-button').click()
78
+ console.log('display:%s', bottomGear.$el.find('#gear-options-wrapper').css('display'))
79
+ })
80
+ it('should collapse the gear menu', () => {
81
+ expect(bottomGear.$el.find('#gear-options-wrapper').css('display')).toBe(
82
+ 'none',
83
+ )
84
+ })
64
85
  })
65
86
  })