@gcorevideo/player 2.28.20 → 2.28.21
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/core.js +1 -1
- package/dist/index.css +259 -259
- package/dist/index.embed.js +94 -23
- package/dist/index.js +95 -24
- package/lib/plugins/audio-selector/AudioTracks.d.ts +2 -0
- package/lib/plugins/audio-selector/AudioTracks.d.ts.map +1 -1
- package/lib/plugins/audio-selector/AudioTracks.js +11 -0
- package/lib/plugins/bottom-gear/BottomGear.d.ts +2 -0
- package/lib/plugins/bottom-gear/BottomGear.d.ts.map +1 -1
- package/lib/plugins/bottom-gear/BottomGear.js +11 -0
- package/lib/plugins/media-control/MediaControl.d.ts +10 -0
- package/lib/plugins/media-control/MediaControl.d.ts.map +1 -1
- package/lib/plugins/media-control/MediaControl.js +20 -23
- package/lib/plugins/subtitles/ClosedCaptions.d.ts +3 -0
- package/lib/plugins/subtitles/ClosedCaptions.d.ts.map +1 -1
- package/lib/plugins/subtitles/ClosedCaptions.js +16 -0
- package/lib/testUtils.d.ts.map +1 -1
- package/lib/testUtils.js +2 -0
- package/lib/utils/clickaway.d.ts +15 -0
- package/lib/utils/clickaway.d.ts.map +1 -0
- package/lib/utils/clickaway.js +40 -0
- package/package.json +1 -1
- package/src/plugins/audio-selector/AudioTracks.ts +15 -1
- package/src/plugins/bottom-gear/BottomGear.ts +13 -0
- package/src/plugins/media-control/MediaControl.ts +20 -25
- package/src/plugins/subtitles/ClosedCaptions.ts +19 -0
- package/src/testUtils.ts +2 -0
- package/src/utils/clickaway.ts +43 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -20,6 +20,7 @@ import volumeMaxIcon from '../../../assets/icons/new/volume-max.svg';
|
|
|
20
20
|
import volumeOffIcon from '../../../assets/icons/new/volume-off.svg';
|
|
21
21
|
import fullscreenOffIcon from '../../../assets/icons/new/fullscreen-off.svg';
|
|
22
22
|
import fullscreenOnIcon from '../../../assets/icons/new/fullscreen-on.svg';
|
|
23
|
+
import { mediaControlClickaway } from '../../utils/clickaway.js';
|
|
23
24
|
const STANDARD_MEDIA_CONTROL_ELEMENTS = [
|
|
24
25
|
'duration',
|
|
25
26
|
'fullscreen',
|
|
@@ -268,6 +269,7 @@ export class MediaControl extends UICorePlugin {
|
|
|
268
269
|
}
|
|
269
270
|
/**
|
|
270
271
|
* @internal
|
|
272
|
+
* The methods declared here will be exposed via the main player object API
|
|
271
273
|
*/
|
|
272
274
|
getExternalInterface() {
|
|
273
275
|
return {
|
|
@@ -936,6 +938,23 @@ export class MediaControl extends UICorePlugin {
|
|
|
936
938
|
mount(name, element) {
|
|
937
939
|
mountTo(this.getMountParent(name), element);
|
|
938
940
|
}
|
|
941
|
+
/**
|
|
942
|
+
* Set or reset the keep visibility state
|
|
943
|
+
*
|
|
944
|
+
* Keep visibility state controls whether the media control is hidden automatically after a delay.
|
|
945
|
+
* Keep visibility prevents the the auto-hide behaviour
|
|
946
|
+
*
|
|
947
|
+
* @param keepVisible - The state
|
|
948
|
+
*/
|
|
949
|
+
setKeepVisible(keepVisible) {
|
|
950
|
+
this.keepVisible = keepVisible;
|
|
951
|
+
if (keepVisible) {
|
|
952
|
+
this.clickaway(this.core.activeContainer.$el[0]);
|
|
953
|
+
}
|
|
954
|
+
else {
|
|
955
|
+
this.clickaway(null);
|
|
956
|
+
}
|
|
957
|
+
}
|
|
939
958
|
getMountParent(name) {
|
|
940
959
|
switch (name) {
|
|
941
960
|
case 'root':
|
|
@@ -1235,13 +1254,7 @@ export class MediaControl extends UICorePlugin {
|
|
|
1235
1254
|
delayHide() {
|
|
1236
1255
|
this.hide(this.options.hideMediaControlDelay || DEFAULT_HIDE_DELAY);
|
|
1237
1256
|
}
|
|
1238
|
-
|
|
1239
|
-
// as opposed to the click event
|
|
1240
|
-
clickaway = clickaway(() => {
|
|
1241
|
-
if (Browser.isMobile) {
|
|
1242
|
-
setTimeout(this.resetUserKeepVisible, 0);
|
|
1243
|
-
}
|
|
1244
|
-
});
|
|
1257
|
+
clickaway = mediaControlClickaway(() => this.resetUserKeepVisible());
|
|
1245
1258
|
}
|
|
1246
1259
|
MediaControl.extend = function (properties) {
|
|
1247
1260
|
return extend(MediaControl, properties);
|
|
@@ -1282,19 +1295,3 @@ function mergeElements(a, b) {
|
|
|
1282
1295
|
return acc;
|
|
1283
1296
|
}, a);
|
|
1284
1297
|
}
|
|
1285
|
-
function clickaway(callback) {
|
|
1286
|
-
let handler = (event) => { };
|
|
1287
|
-
return (node) => {
|
|
1288
|
-
window.removeEventListener('click', handler);
|
|
1289
|
-
if (!node) {
|
|
1290
|
-
return;
|
|
1291
|
-
}
|
|
1292
|
-
handler = (event) => {
|
|
1293
|
-
if (!node.contains(event.target)) {
|
|
1294
|
-
window.removeEventListener('click', handler);
|
|
1295
|
-
callback();
|
|
1296
|
-
}
|
|
1297
|
-
};
|
|
1298
|
-
window.addEventListener('click', handler);
|
|
1299
|
-
};
|
|
1300
|
-
}
|
|
@@ -114,6 +114,7 @@ export declare class ClosedCaptions extends UICorePlugin {
|
|
|
114
114
|
private applyPreselectedSubtitles;
|
|
115
115
|
private hideMenu;
|
|
116
116
|
private toggleMenu;
|
|
117
|
+
private setKeepVisible;
|
|
117
118
|
private itemElement;
|
|
118
119
|
private allItemElements;
|
|
119
120
|
private selectSubtitles;
|
|
@@ -125,5 +126,7 @@ export declare class ClosedCaptions extends UICorePlugin {
|
|
|
125
126
|
private renderIcon;
|
|
126
127
|
private clampPopup;
|
|
127
128
|
private mount;
|
|
129
|
+
private get shouldKeepVisible();
|
|
130
|
+
private clickaway;
|
|
128
131
|
}
|
|
129
132
|
//# sourceMappingURL=ClosedCaptions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ClosedCaptions.d.ts","sourceRoot":"","sources":["../../../src/plugins/subtitles/ClosedCaptions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,YAAY,EAAwB,MAAM,cAAc,CAAA;AAOzE,OAAO,sCAAsC,CAAA;
|
|
1
|
+
{"version":3,"file":"ClosedCaptions.d.ts","sourceRoot":"","sources":["../../../src/plugins/subtitles/ClosedCaptions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,YAAY,EAAwB,MAAM,cAAc,CAAA;AAOzE,OAAO,sCAAsC,CAAA;AAiB7C;;;GAGG;AACH,MAAM,MAAM,4BAA4B,GAAG;IACzC;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,qBAAa,cAAe,SAAQ,YAAY;IAC9C,OAAO,CAAC,oBAAoB,CAAQ;IAEpC,OAAO,CAAC,MAAM,CAAQ;IAEtB,OAAO,CAAC,IAAI,CAAQ;IAEpB,OAAO,CAAC,KAAK,CAA6B;IAE1C,OAAO,CAAC,MAAM,CAAsB;IAEpC,OAAO,CAAC,KAAK,CAA2B;IAExC;;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,eAAe,CAAyB;IAEhE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAuB;IAE3D;;OAEG;IACH,IAAa,UAAU;;MAItB;IAED;;OAEG;IACH,IAAa,MAAM;;;MAKlB;IAED,OAAO,KAAK,mBAAmB,GAK9B;IAED;;OAEG;IACM,UAAU;IASnB,OAAO,CAAC,WAAW;IAkBnB,OAAO,CAAC,kBAAkB;IAmD1B,OAAO,CAAC,mBAAmB;IAQ3B,OAAO,CAAC,iBAAiB;IAkCzB,OAAO,CAAC,WAAW;IAUnB,OAAO,CAAC,SAAS;IAWjB,OAAO,CAAC,UAAU;IASlB,OAAO,CAAC,iBAAiB;IAqBzB;;OAEG;IACH,IAAI;IAcJ;;OAEG;IACH,IAAI;IAiBJ,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,UAAU;IAUlB;;OAEG;IACM,MAAM;IA4Bf,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,UAAU;IAOlB,OAAO,CAAC,YAAY;IAYpB,OAAO,CAAC,yBAAyB;IAejC,OAAO,CAAC,QAAQ;IAOhB,OAAO,CAAC,UAAU;IAclB,OAAO,CAAC,cAAc;IAOtB,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,eAAe;IAQvB,OAAO,CAAC,eAAe;IAiBvB,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,iBAAiB;IAIzB,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,yBAAyB;IAiBjC,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,UAAU;IAOlB,OAAO,CAAC,KAAK;IAOb,OAAO,KAAK,iBAAiB,GAE5B;IAED,OAAO,CAAC,SAAS,CAA+C;CACjE"}
|
|
@@ -9,6 +9,7 @@ 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
11
|
import { ExtendedEvents } from '../media-control/MediaControl.js';
|
|
12
|
+
import { mediaControlClickaway } from '../../utils/clickaway.js';
|
|
12
13
|
const VERSION = '2.19.14';
|
|
13
14
|
const LOCAL_STORAGE_CC_ID = 'gplayer.plugins.cc.selected';
|
|
14
15
|
const T = 'plugins.cc';
|
|
@@ -118,6 +119,9 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
118
119
|
onContainerChanged() {
|
|
119
120
|
this.listenTo(this.core.activeContainer, Events.CONTAINER_FULLSCREEN, this.onContainerResize);
|
|
120
121
|
this.listenTo(this.core.activeContainer, Events.CONTAINER_RESIZE, this.onContainerResize);
|
|
122
|
+
this.listenTo(this.core.activeContainer, Events.CONTAINER_DESTROYED, () => {
|
|
123
|
+
this.clickaway(null);
|
|
124
|
+
});
|
|
121
125
|
this.listenTo(this.core.activeContainer, 'container:advertisement:start', this.onStartAd);
|
|
122
126
|
this.listenTo(this.core.activePlayback, Events.PLAYBACK_SUBTITLE_AVAILABLE, this.onSubtitleAvailable);
|
|
123
127
|
this.listenTo(this.core.activePlayback, Events.PLAYBACK_SUBTITLE_CHANGED, this.onSubtitleChanged);
|
|
@@ -315,6 +319,7 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
315
319
|
this.open = false;
|
|
316
320
|
this.$el.find('#gplayer-cc-menu').hide();
|
|
317
321
|
this.$el.find('#gplayer-cc-button').attr('aria-expanded', 'false');
|
|
322
|
+
this.setKeepVisible(false);
|
|
318
323
|
}
|
|
319
324
|
toggleMenu() {
|
|
320
325
|
this.core
|
|
@@ -328,6 +333,13 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
328
333
|
this.$el.find('#gplayer-cc-menu').hide();
|
|
329
334
|
}
|
|
330
335
|
this.$el.find('#gplayer-cc-button').attr('aria-expanded', this.open);
|
|
336
|
+
this.setKeepVisible(this.open);
|
|
337
|
+
}
|
|
338
|
+
setKeepVisible(keepVisible) {
|
|
339
|
+
if (this.shouldKeepVisible) {
|
|
340
|
+
this.core.getPlugin('media_control').setKeepVisible(keepVisible);
|
|
341
|
+
this.clickaway(keepVisible ? this.core.activeContainer.$el[0] : null);
|
|
342
|
+
}
|
|
331
343
|
}
|
|
332
344
|
itemElement(id) {
|
|
333
345
|
// TODO fix semantically
|
|
@@ -402,4 +414,8 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
402
414
|
mediaControl.slot('cc', this.$el);
|
|
403
415
|
}
|
|
404
416
|
}
|
|
417
|
+
get shouldKeepVisible() {
|
|
418
|
+
return !!this.options.cc?.keepVisible;
|
|
419
|
+
}
|
|
420
|
+
clickaway = mediaControlClickaway(() => this.hideMenu());
|
|
405
421
|
}
|
package/lib/testUtils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testUtils.d.ts","sourceRoot":"","sources":["../src/testUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAK,YAAY,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,MAAM,MAAM,eAAe,CAAA;AAGlC,wBAAgB,cAAc,CAC5B,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACrC,SAAS,GAAE,GAAkC;;;;;;;;;;;;;;;;;EAsB9C;AAED,wBAAgB,gBAAgB;;;EAK/B;AAED,wBAAgB,mBAAmB;;;;;;EAKlC;AAED,wBAAgB,kBAAkB,CAChC,IAAI,SAAS,EACb,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqCtC;AAED,wBAAgB,mBAAmB,CACjC,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACrC,QAAQ,GAAE,GAAgD;;;;;;;;;;;;;;;;;;;;;;;;;EA8B3D;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,GAAG,
|
|
1
|
+
{"version":3,"file":"testUtils.d.ts","sourceRoot":"","sources":["../src/testUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAK,YAAY,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,MAAM,MAAM,eAAe,CAAA;AAGlC,wBAAgB,cAAc,CAC5B,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACrC,SAAS,GAAE,GAAkC;;;;;;;;;;;;;;;;;EAsB9C;AAED,wBAAgB,gBAAgB;;;EAK/B;AAED,wBAAgB,mBAAmB;;;;;;EAKlC;AAED,wBAAgB,kBAAkB,CAChC,IAAI,SAAS,EACb,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqCtC;AAED,wBAAgB,mBAAmB,CACjC,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACrC,QAAQ,GAAE,GAAgD;;;;;;;;;;;;;;;;;;;;;;;;;EA8B3D;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,GAAG,gBAyB/C;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,GAAG,OAe7C"}
|
package/lib/testUtils.js
CHANGED
|
@@ -120,6 +120,8 @@ export function createMockMediaControl(core) {
|
|
|
120
120
|
mediaControl.getAvailablePopupHeight = vi.fn().mockReturnValue(286);
|
|
121
121
|
// @ts-ignore
|
|
122
122
|
mediaControl.toggleElement = vi.fn();
|
|
123
|
+
// @ts-ignore
|
|
124
|
+
mediaControl.setKeepVisible = vi.fn();
|
|
123
125
|
vi.spyOn(mediaControl, 'trigger');
|
|
124
126
|
core.$el.append(mediaControl.$el);
|
|
125
127
|
return mediaControl;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* @param {() => void} callback - The callback to call when the user clicks away from the element
|
|
4
|
+
* @returns {(HTMLElement | null) => void}
|
|
5
|
+
*/
|
|
6
|
+
export declare function clickaway(callback: () => void): (node: HTMLElement | null) => void;
|
|
7
|
+
/**
|
|
8
|
+
* Sets up a clickaway handler for the media control on mobile devices.
|
|
9
|
+
* The handler is deferred to ensure it is called after the next event loop tick.
|
|
10
|
+
*
|
|
11
|
+
* @param {() => void} callback - The callback to call when the user clicks away from the media control
|
|
12
|
+
* @returns {(HTMLElement | null) => void}
|
|
13
|
+
*/
|
|
14
|
+
export declare function mediaControlClickaway(callback: () => void): (node: HTMLElement | null) => void;
|
|
15
|
+
//# sourceMappingURL=clickaway.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clickaway.d.ts","sourceRoot":"","sources":["../../src/utils/clickaway.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,IAGlC,MAAM,WAAW,GAAG,IAAI,UAanC;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,IAAI,UAKxC,WAAW,GAAG,IAAI,UAKnC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Browser } from '@clappr/core';
|
|
2
|
+
/**
|
|
3
|
+
*
|
|
4
|
+
* @param {() => void} callback - The callback to call when the user clicks away from the element
|
|
5
|
+
* @returns {(HTMLElement | null) => void}
|
|
6
|
+
*/
|
|
7
|
+
export function clickaway(callback) {
|
|
8
|
+
let handler = (event) => { };
|
|
9
|
+
return (node) => {
|
|
10
|
+
window.removeEventListener('click', handler);
|
|
11
|
+
if (!node) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
handler = (event) => {
|
|
15
|
+
if (!node.contains(event.target)) {
|
|
16
|
+
window.removeEventListener('click', handler);
|
|
17
|
+
callback();
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
window.addEventListener('click', handler);
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Sets up a clickaway handler for the media control on mobile devices.
|
|
25
|
+
* The handler is deferred to ensure it is called after the next event loop tick.
|
|
26
|
+
*
|
|
27
|
+
* @param {() => void} callback - The callback to call when the user clicks away from the media control
|
|
28
|
+
* @returns {(HTMLElement | null) => void}
|
|
29
|
+
*/
|
|
30
|
+
export function mediaControlClickaway(callback) {
|
|
31
|
+
if (!Browser.isMobile) {
|
|
32
|
+
return () => { };
|
|
33
|
+
}
|
|
34
|
+
const cw = clickaway(callback);
|
|
35
|
+
return (node) => {
|
|
36
|
+
setTimeout(() => {
|
|
37
|
+
cw(node);
|
|
38
|
+
}, 0);
|
|
39
|
+
};
|
|
40
|
+
}
|
package/package.json
CHANGED
|
@@ -9,6 +9,7 @@ import pluginHtml from '../../../assets/audio-tracks/template.ejs'
|
|
|
9
9
|
import audioArrow from '../../../assets/icons/old/quality-arrow.svg'
|
|
10
10
|
import { ZeptoResult } from '../../types.js'
|
|
11
11
|
import { ExtendedEvents, MediaControl } from '../media-control/MediaControl.js'
|
|
12
|
+
import { mediaControlClickaway } from '../../utils/clickaway.js'
|
|
12
13
|
|
|
13
14
|
const VERSION: string = '2.22.4'
|
|
14
15
|
|
|
@@ -132,6 +133,9 @@ export class AudioTracks extends UICorePlugin {
|
|
|
132
133
|
this.listenTo(this.core.activeContainer, Events.CONTAINER_CLICK, () => {
|
|
133
134
|
this.hideMenu()
|
|
134
135
|
})
|
|
136
|
+
this.listenTo(this.core.activeContainer, Events.CONTAINER_DESTROYED, () => {
|
|
137
|
+
this.clickaway(null)
|
|
138
|
+
})
|
|
135
139
|
}
|
|
136
140
|
|
|
137
141
|
private shouldRender() {
|
|
@@ -179,6 +183,7 @@ export class AudioTracks extends UICorePlugin {
|
|
|
179
183
|
this.open = false
|
|
180
184
|
this.$el.find('#gplayer-audiotracks-menu').hide()
|
|
181
185
|
this.$el.find('#gplayer-audiotracks-button').attr('aria-expanded', 'false')
|
|
186
|
+
this.setKeepVisible(false)
|
|
182
187
|
}
|
|
183
188
|
|
|
184
189
|
private toggleMenu() {
|
|
@@ -195,6 +200,13 @@ export class AudioTracks extends UICorePlugin {
|
|
|
195
200
|
this.$el
|
|
196
201
|
.find('#gplayer-audiotracks-button')
|
|
197
202
|
.attr('aria-expanded', this.open)
|
|
203
|
+
|
|
204
|
+
this.setKeepVisible(this.open)
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
private setKeepVisible(keepVisible: boolean) {
|
|
208
|
+
this.core.getPlugin('media_control').setKeepVisible(keepVisible)
|
|
209
|
+
this.clickaway(keepVisible ? this.core.activeContainer.$el[0] : null)
|
|
198
210
|
}
|
|
199
211
|
|
|
200
212
|
private buttonElement(): ZeptoResult {
|
|
@@ -209,7 +221,7 @@ export class AudioTracks extends UICorePlugin {
|
|
|
209
221
|
return (
|
|
210
222
|
this.$(
|
|
211
223
|
'#gplayer-audiotracks-menu a' +
|
|
212
|
-
|
|
224
|
+
(id !== undefined ? `[data-item="${id}"]` : ''),
|
|
213
225
|
) as ZeptoResult
|
|
214
226
|
).parent()
|
|
215
227
|
}
|
|
@@ -253,4 +265,6 @@ export class AudioTracks extends UICorePlugin {
|
|
|
253
265
|
this.core.getPlugin('media_control')?.slot('audiotracks', this.$el)
|
|
254
266
|
}
|
|
255
267
|
}
|
|
268
|
+
|
|
269
|
+
private clickaway = mediaControlClickaway(() => this.hideMenu())
|
|
256
270
|
}
|
|
@@ -17,6 +17,7 @@ import gearIcon from '../../../assets/icons/new/gear.svg'
|
|
|
17
17
|
import gearHdIcon from '../../../assets/icons/new/gear-hd.svg'
|
|
18
18
|
import { ZeptoResult } from '../../types.js'
|
|
19
19
|
import { ExtendedEvents } from '../media-control/MediaControl.js'
|
|
20
|
+
import { mediaControlClickaway } from '../../utils/clickaway.js'
|
|
20
21
|
|
|
21
22
|
const VERSION = '2.19.12'
|
|
22
23
|
|
|
@@ -214,6 +215,9 @@ export class BottomGear extends UICorePlugin {
|
|
|
214
215
|
this.listenTo(container, ClapprEvents.CONTAINER_CLICK, () => {
|
|
215
216
|
this.collapse()
|
|
216
217
|
})
|
|
218
|
+
this.listenTo(container, ClapprEvents.CONTAINER_DESTROYED, () => {
|
|
219
|
+
this.clickaway(null)
|
|
220
|
+
})
|
|
217
221
|
}
|
|
218
222
|
|
|
219
223
|
private highDefinitionUpdate(isHd: boolean) {
|
|
@@ -272,6 +276,12 @@ export class BottomGear extends UICorePlugin {
|
|
|
272
276
|
this.$el
|
|
273
277
|
.find('#gear-button')
|
|
274
278
|
.attr('aria-expanded', (!this.collapsed).toString())
|
|
279
|
+
this.setKeepVisible(!this.collapsed)
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
private setKeepVisible(keepVisible: boolean) {
|
|
283
|
+
this.core.getPlugin('media_control').setKeepVisible(keepVisible)
|
|
284
|
+
this.clickaway(keepVisible ? this.core.activeContainer.$el[0] : null)
|
|
275
285
|
}
|
|
276
286
|
|
|
277
287
|
private collapse() {
|
|
@@ -280,6 +290,7 @@ export class BottomGear extends UICorePlugin {
|
|
|
280
290
|
this.$el.find('#gear-button').attr('aria-expanded', 'false')
|
|
281
291
|
// TODO hide submenus
|
|
282
292
|
this.collapseSubmenus()
|
|
293
|
+
this.setKeepVisible(false)
|
|
283
294
|
}
|
|
284
295
|
|
|
285
296
|
private onCoreReady() {
|
|
@@ -328,4 +339,6 @@ export class BottomGear extends UICorePlugin {
|
|
|
328
339
|
.find('.gear-sub-menu')
|
|
329
340
|
.css('max-height', `${availableHeight - MENU_BACKLINK_HEIGHT}px`)
|
|
330
341
|
}
|
|
342
|
+
|
|
343
|
+
private clickaway = mediaControlClickaway(() => this.collapse())
|
|
331
344
|
}
|
|
@@ -37,6 +37,7 @@ import volumeMaxIcon from '../../../assets/icons/new/volume-max.svg'
|
|
|
37
37
|
import volumeOffIcon from '../../../assets/icons/new/volume-off.svg'
|
|
38
38
|
import fullscreenOffIcon from '../../../assets/icons/new/fullscreen-off.svg'
|
|
39
39
|
import fullscreenOnIcon from '../../../assets/icons/new/fullscreen-on.svg'
|
|
40
|
+
import { mediaControlClickaway } from '../../utils/clickaway.js'
|
|
40
41
|
|
|
41
42
|
const STANDARD_MEDIA_CONTROL_ELEMENTS: string[] = [
|
|
42
43
|
'duration',
|
|
@@ -399,6 +400,7 @@ export class MediaControl extends UICorePlugin {
|
|
|
399
400
|
|
|
400
401
|
/**
|
|
401
402
|
* @internal
|
|
403
|
+
* The methods declared here will be exposed via the main player object API
|
|
402
404
|
*/
|
|
403
405
|
override getExternalInterface() {
|
|
404
406
|
return {
|
|
@@ -1267,6 +1269,23 @@ export class MediaControl extends UICorePlugin {
|
|
|
1267
1269
|
mountTo(this.getMountParent(name), element)
|
|
1268
1270
|
}
|
|
1269
1271
|
|
|
1272
|
+
/**
|
|
1273
|
+
* Set or reset the keep visibility state
|
|
1274
|
+
*
|
|
1275
|
+
* Keep visibility state controls whether the media control is hidden automatically after a delay.
|
|
1276
|
+
* Keep visibility prevents the the auto-hide behaviour
|
|
1277
|
+
*
|
|
1278
|
+
* @param keepVisible - The state
|
|
1279
|
+
*/
|
|
1280
|
+
setKeepVisible(keepVisible: boolean) {
|
|
1281
|
+
this.keepVisible = keepVisible
|
|
1282
|
+
if (keepVisible) {
|
|
1283
|
+
this.clickaway(this.core.activeContainer.$el[0])
|
|
1284
|
+
} else {
|
|
1285
|
+
this.clickaway(null)
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1270
1289
|
private getMountParent(name: MediaControlSlotMountPoint): ZeptoResult {
|
|
1271
1290
|
switch (name) {
|
|
1272
1291
|
case 'root':
|
|
@@ -1628,13 +1647,7 @@ export class MediaControl extends UICorePlugin {
|
|
|
1628
1647
|
this.hide(this.options.hideMediaControlDelay || DEFAULT_HIDE_DELAY)
|
|
1629
1648
|
}
|
|
1630
1649
|
|
|
1631
|
-
|
|
1632
|
-
// as opposed to the click event
|
|
1633
|
-
private clickaway = clickaway(() => {
|
|
1634
|
-
if (Browser.isMobile) {
|
|
1635
|
-
setTimeout(this.resetUserKeepVisible, 0)
|
|
1636
|
-
}
|
|
1637
|
-
})
|
|
1650
|
+
private clickaway = mediaControlClickaway(() => this.resetUserKeepVisible())
|
|
1638
1651
|
}
|
|
1639
1652
|
|
|
1640
1653
|
MediaControl.extend = function (properties) {
|
|
@@ -1688,21 +1701,3 @@ function mergeElements(
|
|
|
1688
1701
|
return acc
|
|
1689
1702
|
}, a)
|
|
1690
1703
|
}
|
|
1691
|
-
|
|
1692
|
-
function clickaway(callback: () => void) {
|
|
1693
|
-
let handler = (event: MouseEvent | TouchEvent) => {}
|
|
1694
|
-
|
|
1695
|
-
return (node: HTMLElement | null) => {
|
|
1696
|
-
window.removeEventListener('click', handler)
|
|
1697
|
-
if (!node) {
|
|
1698
|
-
return
|
|
1699
|
-
}
|
|
1700
|
-
handler = (event: MouseEvent | TouchEvent) => {
|
|
1701
|
-
if (!node.contains(event.target as Node)) {
|
|
1702
|
-
window.removeEventListener('click', handler)
|
|
1703
|
-
callback()
|
|
1704
|
-
}
|
|
1705
|
-
}
|
|
1706
|
-
window.addEventListener('click', handler)
|
|
1707
|
-
}
|
|
1708
|
-
}
|
|
@@ -14,6 +14,7 @@ import stringHTML from '../../../assets/subtitles/string.ejs'
|
|
|
14
14
|
import { isFullscreen } from '../utils/fullscreen.js'
|
|
15
15
|
import type { ZeptoResult } from '../../types.js'
|
|
16
16
|
import { ExtendedEvents } from '../media-control/MediaControl.js'
|
|
17
|
+
import { mediaControlClickaway } from '../../utils/clickaway.js'
|
|
17
18
|
|
|
18
19
|
const VERSION: string = '2.19.14'
|
|
19
20
|
|
|
@@ -172,6 +173,9 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
172
173
|
Events.CONTAINER_RESIZE,
|
|
173
174
|
this.onContainerResize,
|
|
174
175
|
)
|
|
176
|
+
this.listenTo(this.core.activeContainer, Events.CONTAINER_DESTROYED, () => {
|
|
177
|
+
this.clickaway(null)
|
|
178
|
+
})
|
|
175
179
|
this.listenTo(
|
|
176
180
|
this.core.activeContainer,
|
|
177
181
|
'container:advertisement:start',
|
|
@@ -426,6 +430,7 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
426
430
|
this.open = false
|
|
427
431
|
this.$el.find('#gplayer-cc-menu').hide()
|
|
428
432
|
this.$el.find('#gplayer-cc-button').attr('aria-expanded', 'false')
|
|
433
|
+
this.setKeepVisible(false)
|
|
429
434
|
}
|
|
430
435
|
|
|
431
436
|
private toggleMenu() {
|
|
@@ -439,6 +444,14 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
439
444
|
this.$el.find('#gplayer-cc-menu').hide()
|
|
440
445
|
}
|
|
441
446
|
this.$el.find('#gplayer-cc-button').attr('aria-expanded', this.open)
|
|
447
|
+
this.setKeepVisible(this.open)
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
private setKeepVisible(keepVisible: boolean) {
|
|
451
|
+
if (this.shouldKeepVisible) {
|
|
452
|
+
this.core.getPlugin('media_control').setKeepVisible(keepVisible)
|
|
453
|
+
this.clickaway(keepVisible ? this.core.activeContainer.$el[0] : null)
|
|
454
|
+
}
|
|
442
455
|
}
|
|
443
456
|
|
|
444
457
|
private itemElement(id: number): ZeptoResult {
|
|
@@ -529,4 +542,10 @@ export class ClosedCaptions extends UICorePlugin {
|
|
|
529
542
|
mediaControl.slot('cc', this.$el)
|
|
530
543
|
}
|
|
531
544
|
}
|
|
545
|
+
|
|
546
|
+
private get shouldKeepVisible() {
|
|
547
|
+
return !!this.options.cc?.keepVisible
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
private clickaway = mediaControlClickaway(() => this.hideMenu())
|
|
532
551
|
}
|
package/src/testUtils.ts
CHANGED
|
@@ -137,6 +137,8 @@ export function createMockMediaControl(core: any) {
|
|
|
137
137
|
mediaControl.getAvailablePopupHeight = vi.fn().mockReturnValue(286)
|
|
138
138
|
// @ts-ignore
|
|
139
139
|
mediaControl.toggleElement = vi.fn()
|
|
140
|
+
// @ts-ignore
|
|
141
|
+
mediaControl.setKeepVisible = vi.fn()
|
|
140
142
|
vi.spyOn(mediaControl, 'trigger')
|
|
141
143
|
core.$el.append(mediaControl.$el)
|
|
142
144
|
return mediaControl
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Browser } from '@clappr/core'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* @param {() => void} callback - The callback to call when the user clicks away from the element
|
|
6
|
+
* @returns {(HTMLElement | null) => void}
|
|
7
|
+
*/
|
|
8
|
+
export function clickaway(callback: () => void) {
|
|
9
|
+
let handler = (event: MouseEvent | TouchEvent) => { }
|
|
10
|
+
|
|
11
|
+
return (node: HTMLElement | null) => {
|
|
12
|
+
window.removeEventListener('click', handler)
|
|
13
|
+
if (!node) {
|
|
14
|
+
return
|
|
15
|
+
}
|
|
16
|
+
handler = (event: MouseEvent | TouchEvent) => {
|
|
17
|
+
if (!node.contains(event.target as Node)) {
|
|
18
|
+
window.removeEventListener('click', handler)
|
|
19
|
+
callback()
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
window.addEventListener('click', handler)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Sets up a clickaway handler for the media control on mobile devices.
|
|
28
|
+
* The handler is deferred to ensure it is called after the next event loop tick.
|
|
29
|
+
*
|
|
30
|
+
* @param {() => void} callback - The callback to call when the user clicks away from the media control
|
|
31
|
+
* @returns {(HTMLElement | null) => void}
|
|
32
|
+
*/
|
|
33
|
+
export function mediaControlClickaway(callback: () => void) {
|
|
34
|
+
if (!Browser.isMobile) {
|
|
35
|
+
return () => { }
|
|
36
|
+
}
|
|
37
|
+
const cw = clickaway(callback)
|
|
38
|
+
return (node: HTMLElement | null) => {
|
|
39
|
+
setTimeout(() => {
|
|
40
|
+
cw(node)
|
|
41
|
+
}, 0)
|
|
42
|
+
}
|
|
43
|
+
}
|