@gcorevideo/player 2.24.1 → 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.
package/dist/index.js CHANGED
@@ -43303,7 +43303,7 @@ class Player {
43303
43303
  }
43304
43304
  }
43305
43305
 
43306
- var version$1 = "2.24.1";
43306
+ var version$1 = "2.24.2";
43307
43307
 
43308
43308
  var packages = {
43309
43309
  "node_modules/@clappr/core": {
@@ -43896,6 +43896,15 @@ class MediaControl extends UICorePlugin {
43896
43896
  this.bindKeyEvents();
43897
43897
  this.show();
43898
43898
  }
43899
+ /**
43900
+ *
43901
+ * @returns Vertical space available to render something on top of the container.
43902
+ * @remarks
43903
+ * This takes into account the container height and excludes the height of the controls bar
43904
+ */
43905
+ getAvailableHeight() {
43906
+ return (this.core.$el.height() - this.$el.find('.media-control-layer').height());
43907
+ }
43899
43908
  /**
43900
43909
  * Set the initial volume, which is preserved when playback is interrupted by an advertisement
43901
43910
  */
@@ -43995,11 +44004,11 @@ class MediaControl extends UICorePlugin {
43995
44004
  this.applyButtonStyle(this.$playStopToggle);
43996
44005
  }
43997
44006
  mousemoveOnSeekBar(event) {
43998
- const offset = MediaControl.getPageX(event) -
43999
- (this.$seekBarContainer.offset().left ?? 0); // TODO check if the result can be negative
44000
- const hoverOffset = offset -
44001
- (this.$seekBarHover.width() ?? 0) / 2;
44002
- const pos = offset ? Math.min(1, Math.max(offset / this.$seekBarContainer.width(), 0)) : 0;
44007
+ const offset = MediaControl.getPageX(event) - (this.$seekBarContainer.offset().left ?? 0); // TODO check if the result can be negative
44008
+ const hoverOffset = offset - (this.$seekBarHover.width() ?? 0) / 2;
44009
+ const pos = offset
44010
+ ? Math.min(1, Math.max(offset / this.$seekBarContainer.width(), 0))
44011
+ : 0;
44003
44012
  if (this.settings.seekEnabled) {
44004
44013
  // TODO test that it works when the element does not exist
44005
44014
  this.$seekBarHover.css({ left: hoverOffset });
@@ -45091,6 +45100,8 @@ const gearHdIcon = "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\
45091
45100
 
45092
45101
  const VERSION$6 = '2.19.12';
45093
45102
  const T$g = 'plugins.bottom_gear';
45103
+ const MENU_VMARGIN = 12;
45104
+ const MENU_BACKLINK_HEIGHT = 44;
45094
45105
  /**
45095
45106
  * Events triggered by the plugin
45096
45107
  * @beta
@@ -45102,7 +45113,6 @@ var GearEvents;
45102
45113
  */
45103
45114
  GearEvents["RENDERED"] = "rendered";
45104
45115
  })(GearEvents || (GearEvents = {}));
45105
- // TODO disabled if no items added
45106
45116
  /**
45107
45117
  * `PLUGIN` that adds a button to extend the media controls UI with extra options.
45108
45118
  * @beta
@@ -45239,7 +45249,7 @@ class BottomGear extends UICorePlugin {
45239
45249
  * ```
45240
45250
  */
45241
45251
  addItem(name, $subMenu) {
45242
- const $existingItem = this.$el.find(`#gear-options li[data-${name}`);
45252
+ const $existingItem = this.$el.find(`#gear-options li[data-${name}]`);
45243
45253
  if ($existingItem.length) {
45244
45254
  trace(`${T$g} addItem already exists`, { name });
45245
45255
  return $existingItem;
@@ -45254,20 +45264,17 @@ class BottomGear extends UICorePlugin {
45254
45264
  .hide()
45255
45265
  .appendTo(this.$el.find('#gear-options-wrapper'));
45256
45266
  $item.on('click', (e) => {
45257
- trace(`${T$g} addItem submenu clicked`, { name });
45258
45267
  e.stopPropagation();
45268
+ this.alignSubmenu($subMenu);
45259
45269
  $subMenu.show();
45260
45270
  this.$el.find('#gear-options').hide();
45261
45271
  });
45262
45272
  }
45263
45273
  this.numItems++;
45264
- if (this.numItems > 0) {
45265
- this.$el.show();
45266
- }
45274
+ this.$el.show();
45267
45275
  return $item;
45268
45276
  }
45269
45277
  bindContainerEvents(container) {
45270
- trace(`${T$g} bindContainerEvents`);
45271
45278
  this.listenTo(container, Events$1.CONTAINER_HIGHDEFINITIONUPDATE, this.highDefinitionUpdate);
45272
45279
  this.listenTo(container, Events$1.CONTAINER_CLICK, () => {
45273
45280
  this.collapse();
@@ -45282,7 +45289,6 @@ class BottomGear extends UICorePlugin {
45282
45289
  * @internal
45283
45290
  */
45284
45291
  render() {
45285
- trace(`${T$g} render`);
45286
45292
  const mediaControl = this.core.getPlugin('media_control');
45287
45293
  if (!mediaControl) {
45288
45294
  return this; // TODO test
@@ -45323,11 +45329,11 @@ class BottomGear extends UICorePlugin {
45323
45329
  else {
45324
45330
  this.$el.find('#gear-options-wrapper').show();
45325
45331
  }
45326
- this.$el.find('#gear-button').attr('aria-expanded', (!this.collapsed).toString());
45327
- trace(`${T$g} toggleMenu`, { hidden: this.collapsed });
45332
+ this.$el
45333
+ .find('#gear-button')
45334
+ .attr('aria-expanded', (!this.collapsed).toString());
45328
45335
  }
45329
45336
  collapse() {
45330
- trace(`${T$g} collapse`);
45331
45337
  this.collapsed = true;
45332
45338
  this.$el.find('#gear-options-wrapper').hide();
45333
45339
  this.$el.find('#gear-button').attr('aria-expanded', 'false');
@@ -45335,7 +45341,6 @@ class BottomGear extends UICorePlugin {
45335
45341
  this.collapseSubmenus();
45336
45342
  }
45337
45343
  onCoreReady() {
45338
- trace(`${T$g} onCoreReady`);
45339
45344
  const mediaControl = this.core.getPlugin('media_control');
45340
45345
  assert(mediaControl, 'media_control plugin is required');
45341
45346
  this.listenTo(mediaControl, Events$1.MEDIACONTROL_RENDERED, this.onMediaControlRendered);
@@ -45351,16 +45356,20 @@ class BottomGear extends UICorePlugin {
45351
45356
  this.bindContainerEvents(mediaControl.container);
45352
45357
  }
45353
45358
  onMediaControlRendered() {
45354
- trace(`${T$g} onMediaControlRendered`);
45355
45359
  this.mount();
45356
45360
  }
45357
45361
  mount() {
45358
- trace(`${T$g} mount`, {
45359
- numItems: this.numItems,
45360
- });
45361
45362
  const mediaControl = this.core.getPlugin('media_control');
45362
45363
  mediaControl.mount('gear', this.$el);
45363
45364
  }
45365
+ alignSubmenu($subMenu) {
45366
+ const availableHeight = this.core.getPlugin('media_control').getAvailableHeight() -
45367
+ MENU_VMARGIN * 2;
45368
+ $subMenu.css('max-height', `${availableHeight}px`);
45369
+ $subMenu
45370
+ .find('.gear-sub-menu')
45371
+ .css('max-height', `${availableHeight - MENU_BACKLINK_HEIGHT}px`);
45372
+ }
45364
45373
  }
45365
45374
 
45366
45375
  /**
@@ -156,5 +156,6 @@ export declare class BottomGear extends UICorePlugin {
156
156
  private onCoreReady;
157
157
  private onMediaControlRendered;
158
158
  private mount;
159
+ private alignSubmenu;
159
160
  }
160
161
  //# sourceMappingURL=BottomGear.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"BottomGear.d.ts","sourceRoot":"","sources":["../../../src/plugins/bottom-gear/BottomGear.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAkD,MAAM,cAAc,CAAA;AAO3F,OAAO,uCAAuC,CAAA;AAC9C,OAAO,gDAAgD,CAAA;AAGvD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAO5C;;;GAGG;AACH,oBAAY,UAAU;IACpB;;OAEG;IACH,QAAQ,aAAa;CACtB;AAID;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmEG;AACH,qBAAa,UAAW,SAAQ,YAAY;IAC1C,OAAO,CAAC,EAAE,CAAQ;IAElB,OAAO,CAAC,QAAQ,CAAK;IAErB,OAAO,CAAC,SAAS,CAAQ;IAEzB;;OAEG;IACH,IAAI,IAAI,WAEP;IAED;;OAEG;IACH,IAAI,gBAAgB;;MAEnB;IAED;;OAEG;IACH,MAAM,KAAK,OAAO,WAEjB;IAED,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAuB;IAEvD;;OAEG;IACH,IAAa,UAAU;;MAItB;IAED;;OAEG;IACH,IAAa,MAAM;;MAIlB;IAED;;OAEG;IACM,UAAU;IAInB;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,WAAW,GAAG,WAAW;IA6B1D,OAAO,CAAC,mBAAmB;IAY3B,OAAO,CAAC,oBAAoB;IAM5B;;OAEG;IACM,MAAM;IAsBf;;;;OAIG;IACH,OAAO;IAIP,OAAO,CAAC,gBAAgB;IAKxB,OAAO,CAAC,UAAU;IAclB,OAAO,CAAC,QAAQ;IAShB,OAAO,CAAC,WAAW;IAyBnB,OAAO,CAAC,sBAAsB;IAK9B,OAAO,CAAC,KAAK;CAOd"}
1
+ {"version":3,"file":"BottomGear.d.ts","sourceRoot":"","sources":["../../../src/plugins/bottom-gear/BottomGear.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EAKb,MAAM,cAAc,CAAA;AAOrB,OAAO,uCAAuC,CAAA;AAC9C,OAAO,gDAAgD,CAAA;AAGvD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAU5C;;;GAGG;AACH,oBAAY,UAAU;IACpB;;OAEG;IACH,QAAQ,aAAa;CACtB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmEG;AACH,qBAAa,UAAW,SAAQ,YAAY;IAC1C,OAAO,CAAC,EAAE,CAAQ;IAElB,OAAO,CAAC,QAAQ,CAAI;IAEpB,OAAO,CAAC,SAAS,CAAO;IAExB;;OAEG;IACH,IAAI,IAAI,WAEP;IAED;;OAEG;IACH,IAAI,gBAAgB;;MAEnB;IAED;;OAEG;IACH,MAAM,KAAK,OAAO,WAEjB;IAED,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAuB;IAEvD;;OAEG;IACH,IAAa,UAAU;;MAItB;IAED;;OAEG;IACH,IAAa,MAAM;;MAIlB;IAED;;OAEG;IACM,UAAU;IAInB;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,WAAW,GAAG,WAAW;IA2B1D,OAAO,CAAC,mBAAmB;IAW3B,OAAO,CAAC,oBAAoB;IAM5B;;OAEG;IACM,MAAM;IAqBf;;;;OAIG;IACH,OAAO;IAIP,OAAO,CAAC,gBAAgB;IAKxB,OAAO,CAAC,UAAU;IAelB,OAAO,CAAC,QAAQ;IAQhB,OAAO,CAAC,WAAW;IA4BnB,OAAO,CAAC,sBAAsB;IAI9B,OAAO,CAAC,KAAK;IAKb,OAAO,CAAC,YAAY;CASrB"}
@@ -1,4 +1,4 @@
1
- import { UICorePlugin, template, Events as ClapprEvents, $ } from '@clappr/core';
1
+ import { UICorePlugin, template, Events as ClapprEvents, $, } from '@clappr/core';
2
2
  import { trace } from '@gcorevideo/utils';
3
3
  import assert from 'assert';
4
4
  import { CLAPPR_VERSION } from '../../build.js';
@@ -10,6 +10,8 @@ import gearHdIcon from '../../../assets/icons/new/gear-hd.svg';
10
10
  import { ExtendedEvents } from '../media-control/MediaControl.js';
11
11
  const VERSION = '2.19.12';
12
12
  const T = 'plugins.bottom_gear';
13
+ const MENU_VMARGIN = 12;
14
+ const MENU_BACKLINK_HEIGHT = 44;
13
15
  /**
14
16
  * Events triggered by the plugin
15
17
  * @beta
@@ -21,7 +23,6 @@ export var GearEvents;
21
23
  */
22
24
  GearEvents["RENDERED"] = "rendered";
23
25
  })(GearEvents || (GearEvents = {}));
24
- // TODO disabled if no items added
25
26
  /**
26
27
  * `PLUGIN` that adds a button to extend the media controls UI with extra options.
27
28
  * @beta
@@ -158,7 +159,7 @@ export class BottomGear extends UICorePlugin {
158
159
  * ```
159
160
  */
160
161
  addItem(name, $subMenu) {
161
- const $existingItem = this.$el.find(`#gear-options li[data-${name}`);
162
+ const $existingItem = this.$el.find(`#gear-options li[data-${name}]`);
162
163
  if ($existingItem.length) {
163
164
  trace(`${T} addItem already exists`, { name });
164
165
  return $existingItem;
@@ -173,20 +174,17 @@ export class BottomGear extends UICorePlugin {
173
174
  .hide()
174
175
  .appendTo(this.$el.find('#gear-options-wrapper'));
175
176
  $item.on('click', (e) => {
176
- trace(`${T} addItem submenu clicked`, { name });
177
177
  e.stopPropagation();
178
+ this.alignSubmenu($subMenu);
178
179
  $subMenu.show();
179
180
  this.$el.find('#gear-options').hide();
180
181
  });
181
182
  }
182
183
  this.numItems++;
183
- if (this.numItems > 0) {
184
- this.$el.show();
185
- }
184
+ this.$el.show();
186
185
  return $item;
187
186
  }
188
187
  bindContainerEvents(container) {
189
- trace(`${T} bindContainerEvents`);
190
188
  this.listenTo(container, ClapprEvents.CONTAINER_HIGHDEFINITIONUPDATE, this.highDefinitionUpdate);
191
189
  this.listenTo(container, ClapprEvents.CONTAINER_CLICK, () => {
192
190
  this.collapse();
@@ -201,7 +199,6 @@ export class BottomGear extends UICorePlugin {
201
199
  * @internal
202
200
  */
203
201
  render() {
204
- trace(`${T} render`);
205
202
  const mediaControl = this.core.getPlugin('media_control');
206
203
  if (!mediaControl) {
207
204
  return this; // TODO test
@@ -242,11 +239,11 @@ export class BottomGear extends UICorePlugin {
242
239
  else {
243
240
  this.$el.find('#gear-options-wrapper').show();
244
241
  }
245
- this.$el.find('#gear-button').attr('aria-expanded', (!this.collapsed).toString());
246
- trace(`${T} toggleMenu`, { hidden: this.collapsed });
242
+ this.$el
243
+ .find('#gear-button')
244
+ .attr('aria-expanded', (!this.collapsed).toString());
247
245
  }
248
246
  collapse() {
249
- trace(`${T} collapse`);
250
247
  this.collapsed = true;
251
248
  this.$el.find('#gear-options-wrapper').hide();
252
249
  this.$el.find('#gear-button').attr('aria-expanded', 'false');
@@ -254,7 +251,6 @@ export class BottomGear extends UICorePlugin {
254
251
  this.collapseSubmenus();
255
252
  }
256
253
  onCoreReady() {
257
- trace(`${T} onCoreReady`);
258
254
  const mediaControl = this.core.getPlugin('media_control');
259
255
  assert(mediaControl, 'media_control plugin is required');
260
256
  this.listenTo(mediaControl, ClapprEvents.MEDIACONTROL_RENDERED, this.onMediaControlRendered);
@@ -270,14 +266,18 @@ export class BottomGear extends UICorePlugin {
270
266
  this.bindContainerEvents(mediaControl.container);
271
267
  }
272
268
  onMediaControlRendered() {
273
- trace(`${T} onMediaControlRendered`);
274
269
  this.mount();
275
270
  }
276
271
  mount() {
277
- trace(`${T} mount`, {
278
- numItems: this.numItems,
279
- });
280
272
  const mediaControl = this.core.getPlugin('media_control');
281
273
  mediaControl.mount('gear', this.$el);
282
274
  }
275
+ alignSubmenu($subMenu) {
276
+ const availableHeight = this.core.getPlugin('media_control').getAvailableHeight() -
277
+ MENU_VMARGIN * 2;
278
+ $subMenu.css('max-height', `${availableHeight}px`);
279
+ $subMenu
280
+ .find('.gear-sub-menu')
281
+ .css('max-height', `${availableHeight - MENU_BACKLINK_HEIGHT}px`);
282
+ }
283
283
  }
@@ -183,6 +183,13 @@ export declare class MediaControl extends UICorePlugin {
183
183
  * Reenables the plugin disabled earlier with the {@link MediaControl.disable} method
184
184
  */
185
185
  enable(): void;
186
+ /**
187
+ *
188
+ * @returns Vertical space available to render something on top of the container.
189
+ * @remarks
190
+ * This takes into account the container height and excludes the height of the controls bar
191
+ */
192
+ getAvailableHeight(): number;
186
193
  /**
187
194
  * Set the initial volume, which is preserved when playback is interrupted by an advertisement
188
195
  */
@@ -1 +1 @@
1
- {"version":3,"file":"MediaControl.d.ts","sourceRoot":"","sources":["../../../src/plugins/media-control/MediaControl.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"MediaControl.d.ts","sourceRoot":"","sources":["../../../src/plugins/media-control/MediaControl.ts"],"names":[],"mappings":"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"}
@@ -318,6 +318,15 @@ export class MediaControl extends UICorePlugin {
318
318
  this.bindKeyEvents();
319
319
  this.show();
320
320
  }
321
+ /**
322
+ *
323
+ * @returns Vertical space available to render something on top of the container.
324
+ * @remarks
325
+ * This takes into account the container height and excludes the height of the controls bar
326
+ */
327
+ getAvailableHeight() {
328
+ return (this.core.$el.height() - this.$el.find('.media-control-layer').height());
329
+ }
321
330
  /**
322
331
  * Set the initial volume, which is preserved when playback is interrupted by an advertisement
323
332
  */
@@ -417,11 +426,11 @@ export class MediaControl extends UICorePlugin {
417
426
  this.applyButtonStyle(this.$playStopToggle);
418
427
  }
419
428
  mousemoveOnSeekBar(event) {
420
- const offset = MediaControl.getPageX(event) -
421
- (this.$seekBarContainer.offset().left ?? 0); // TODO check if the result can be negative
422
- const hoverOffset = offset -
423
- (this.$seekBarHover.width() ?? 0) / 2;
424
- const pos = offset ? Math.min(1, Math.max(offset / this.$seekBarContainer.width(), 0)) : 0;
429
+ const offset = MediaControl.getPageX(event) - (this.$seekBarContainer.offset().left ?? 0); // TODO check if the result can be negative
430
+ const hoverOffset = offset - (this.$seekBarHover.width() ?? 0) / 2;
431
+ const pos = offset
432
+ ? Math.min(1, Math.max(offset / this.$seekBarContainer.width(), 0))
433
+ : 0;
425
434
  if (this.settings.seekEnabled) {
426
435
  // TODO test that it works when the element does not exist
427
436
  this.$seekBarHover.css({ left: hoverOffset });
@@ -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,CAAC,IAAI,SAAS,EAAE,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoCtF;AAED,wBAAgB,mBAAmB,CACjC,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACrC,QAAQ,GAAE,GAAgD;;;;;;;;;;;;;;;;;;;;;;;;EA6B3D;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,GAAG,gBAiB/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,CAAC,IAAI,SAAS,EAAE,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoCtF;AAED,wBAAgB,mBAAmB,CACjC,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACrC,QAAQ,GAAE,GAAgD;;;;;;;;;;;;;;;;;;;;;;;;EA6B3D;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,GAAG,gBAmB/C;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,GAAG,OAe7C"}
package/lib/testUtils.js CHANGED
@@ -112,6 +112,8 @@ export function createMockMediaControl(core) {
112
112
  // @ts-ignore
113
113
  mediaControl.container = core.activeContainer;
114
114
  // @ts-ignore
115
+ mediaControl.getAvailableHeight = vi.fn().mockReturnValue(300);
116
+ // @ts-ignore
115
117
  mediaControl.toggleElement = vi.fn();
116
118
  vi.spyOn(mediaControl, 'trigger');
117
119
  core.$el.append(mediaControl.$el);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gcorevideo/player",
3
- "version": "2.24.1",
3
+ "version": "2.24.2",
4
4
  "description": "Gcore JavaScript video player",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -1,4 +1,10 @@
1
- import { UICorePlugin, template, Events as ClapprEvents, $, Container } from '@clappr/core'
1
+ import {
2
+ UICorePlugin,
3
+ template,
4
+ Events as ClapprEvents,
5
+ $,
6
+ Container,
7
+ } from '@clappr/core'
2
8
  import { trace } from '@gcorevideo/utils'
3
9
  import assert from 'assert'
4
10
 
@@ -16,6 +22,9 @@ const VERSION = '2.19.12'
16
22
 
17
23
  const T = 'plugins.bottom_gear'
18
24
 
25
+ const MENU_VMARGIN = 12
26
+ const MENU_BACKLINK_HEIGHT = 44
27
+
19
28
  /**
20
29
  * Events triggered by the plugin
21
30
  * @beta
@@ -27,8 +36,6 @@ export enum GearEvents {
27
36
  RENDERED = 'rendered',
28
37
  }
29
38
 
30
- // TODO disabled if no items added
31
-
32
39
  /**
33
40
  * `PLUGIN` that adds a button to extend the media controls UI with extra options.
34
41
  * @beta
@@ -100,9 +107,9 @@ export enum GearEvents {
100
107
  export class BottomGear extends UICorePlugin {
101
108
  private hd = false
102
109
 
103
- private numItems = 0;
110
+ private numItems = 0
104
111
 
105
- private collapsed = true;
112
+ private collapsed = true
106
113
 
107
114
  /**
108
115
  * @internal
@@ -175,7 +182,7 @@ export class BottomGear extends UICorePlugin {
175
182
  * ```
176
183
  */
177
184
  addItem(name: string, $subMenu?: ZeptoResult): ZeptoResult {
178
- const $existingItem = this.$el.find(`#gear-options li[data-${name}`)
185
+ const $existingItem = this.$el.find(`#gear-options li[data-${name}]`)
179
186
  if ($existingItem.length) {
180
187
  trace(`${T} addItem already exists`, { name })
181
188
  return $existingItem
@@ -190,21 +197,18 @@ export class BottomGear extends UICorePlugin {
190
197
  .hide()
191
198
  .appendTo(this.$el.find('#gear-options-wrapper'))
192
199
  $item.on('click', (e: MouseEvent) => {
193
- trace(`${T} addItem submenu clicked`, { name })
194
200
  e.stopPropagation()
201
+ this.alignSubmenu($subMenu)
195
202
  $subMenu.show()
196
203
  this.$el.find('#gear-options').hide()
197
204
  })
198
205
  }
199
- this.numItems++;
200
- if (this.numItems > 0) {
201
- this.$el.show()
202
- }
206
+ this.numItems++
207
+ this.$el.show()
203
208
  return $item
204
209
  }
205
210
 
206
211
  private bindContainerEvents(container: Container) {
207
- trace(`${T} bindContainerEvents`)
208
212
  this.listenTo(
209
213
  container,
210
214
  ClapprEvents.CONTAINER_HIGHDEFINITIONUPDATE,
@@ -225,14 +229,13 @@ export class BottomGear extends UICorePlugin {
225
229
  * @internal
226
230
  */
227
231
  override render() {
228
- trace(`${T} render`)
229
232
  const mediaControl = this.core.getPlugin('media_control')
230
233
  if (!mediaControl) {
231
234
  return this // TODO test
232
235
  }
233
236
  const icon = this.hd ? gearHdIcon : gearIcon
234
- this.collapsed = true;
235
- this.numItems = 0;
237
+ this.collapsed = true
238
+ this.numItems = 0
236
239
  this.$el
237
240
  .html(BottomGear.template({ icon }))
238
241
  .hide() // until numItems > 0
@@ -264,19 +267,19 @@ export class BottomGear extends UICorePlugin {
264
267
  this.core
265
268
  .getPlugin('media_control')
266
269
  .trigger(ExtendedEvents.MEDIACONTROL_MENU_COLLAPSE, this.name)
267
- this.collapsed = !this.collapsed;
270
+ this.collapsed = !this.collapsed
268
271
  if (this.collapsed) {
269
272
  this.$el.find('#gear-options-wrapper').hide()
270
273
  } else {
271
274
  this.$el.find('#gear-options-wrapper').show()
272
275
  }
273
- this.$el.find('#gear-button').attr('aria-expanded', (!this.collapsed).toString())
274
- trace(`${T} toggleMenu`, { hidden: this.collapsed })
276
+ this.$el
277
+ .find('#gear-button')
278
+ .attr('aria-expanded', (!this.collapsed).toString())
275
279
  }
276
280
 
277
281
  private collapse() {
278
- trace(`${T} collapse`)
279
- this.collapsed = true;
282
+ this.collapsed = true
280
283
  this.$el.find('#gear-options-wrapper').hide()
281
284
  this.$el.find('#gear-button').attr('aria-expanded', 'false')
282
285
  // TODO hide submenus
@@ -284,7 +287,6 @@ export class BottomGear extends UICorePlugin {
284
287
  }
285
288
 
286
289
  private onCoreReady() {
287
- trace(`${T} onCoreReady`)
288
290
  const mediaControl = this.core.getPlugin('media_control')
289
291
  assert(mediaControl, 'media_control plugin is required')
290
292
  this.listenTo(
@@ -293,9 +295,13 @@ export class BottomGear extends UICorePlugin {
293
295
  this.onMediaControlRendered,
294
296
  )
295
297
  this.listenTo(mediaControl, ClapprEvents.MEDIACONTROL_HIDE, this.collapse)
296
- this.listenTo(mediaControl, ClapprEvents.MEDIACONTROL_CONTAINERCHANGED, () => {
297
- this.bindContainerEvents(mediaControl.container)
298
- })
298
+ this.listenTo(
299
+ mediaControl,
300
+ ClapprEvents.MEDIACONTROL_CONTAINERCHANGED,
301
+ () => {
302
+ this.bindContainerEvents(mediaControl.container)
303
+ },
304
+ )
299
305
  this.listenTo(
300
306
  mediaControl,
301
307
  ExtendedEvents.MEDIACONTROL_MENU_COLLAPSE,
@@ -309,15 +315,21 @@ export class BottomGear extends UICorePlugin {
309
315
  }
310
316
 
311
317
  private onMediaControlRendered() {
312
- trace(`${T} onMediaControlRendered`)
313
318
  this.mount()
314
319
  }
315
320
 
316
321
  private mount() {
317
- trace(`${T} mount`, {
318
- numItems: this.numItems,
319
- })
320
322
  const mediaControl = this.core.getPlugin('media_control')
321
323
  mediaControl.mount('gear', this.$el)
322
324
  }
325
+
326
+ private alignSubmenu($subMenu: ZeptoResult) {
327
+ const availableHeight =
328
+ this.core.getPlugin('media_control').getAvailableHeight() -
329
+ MENU_VMARGIN * 2
330
+ $subMenu.css('max-height', `${availableHeight}px`)
331
+ $subMenu
332
+ .find('.gear-sub-menu')
333
+ .css('max-height', `${availableHeight - MENU_BACKLINK_HEIGHT}px`)
334
+ }
323
335
  }
@@ -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
  `;
@@ -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 })