@gcorevideo/player 2.19.14 → 2.19.15
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/assets/level-selector/list.ejs +2 -2
- package/dist/core.js +1 -1
- package/dist/index.css +1054 -1054
- package/dist/index.js +1232 -1154
- package/dist/player.d.ts +157 -22
- package/dist/plugins/index.css +634 -634
- package/dist/plugins/index.js +1024 -944
- package/docs/api/player.bottomgear.getelement.md +56 -0
- package/docs/api/player.bottomgear.md +51 -0
- package/docs/api/player.bottomgear.setcontent.md +56 -0
- package/docs/api/{player.subtitles.levelelement.md → player.gearevents.md} +11 -13
- package/docs/api/{player.sourcecontroller.name.md → player.gearitemelement.md} +5 -3
- package/docs/api/player.levelselector.md +9 -1
- package/docs/api/player.md +37 -0
- package/docs/api/{player.sourcecontroller.supportedversion.md → player.mediacontrol.getrightpanel.md} +11 -5
- package/docs/api/player.mediacontrol.md +14 -0
- package/docs/api/player.mediacontrolelement.md +1 -1
- package/docs/api/player.sourcecontroller.md +0 -90
- package/docs/api/player.spinnerevents.md +49 -0
- package/docs/api/player.spinnerthreebounce._constructor_.md +3 -0
- package/docs/api/player.spinnerthreebounce.hide.md +5 -0
- package/docs/api/player.spinnerthreebounce.md +14 -95
- package/docs/api/player.spinnerthreebounce.show.md +6 -37
- package/docs/api/player.subtitles.hide.md +5 -0
- package/docs/api/player.subtitles.md +23 -275
- package/docs/api/player.subtitles.show.md +5 -0
- package/lib/plugins/bottom-gear/BottomGear.d.ts +20 -1
- package/lib/plugins/bottom-gear/BottomGear.d.ts.map +1 -1
- package/lib/plugins/bottom-gear/BottomGear.js +28 -7
- package/lib/plugins/clappr-nerd-stats/ClapprNerdStats.js +4 -4
- package/lib/plugins/level-selector/LevelSelector.d.ts +10 -3
- package/lib/plugins/level-selector/LevelSelector.d.ts.map +1 -1
- package/lib/plugins/level-selector/LevelSelector.js +20 -19
- package/lib/plugins/media-control/MediaControl.d.ts +6 -2
- package/lib/plugins/media-control/MediaControl.d.ts.map +1 -1
- package/lib/plugins/media-control/MediaControl.js +40 -39
- package/lib/plugins/source-controller/SourceController.d.ts +9 -0
- package/lib/plugins/source-controller/SourceController.d.ts.map +1 -1
- package/lib/plugins/source-controller/SourceController.js +11 -1
- package/lib/plugins/spinner-three-bounce/SpinnerThreeBounce.d.ts +35 -1
- package/lib/plugins/spinner-three-bounce/SpinnerThreeBounce.d.ts.map +1 -1
- package/lib/plugins/spinner-three-bounce/SpinnerThreeBounce.js +46 -23
- package/lib/plugins/subtitles/Subtitles.d.ts +65 -16
- package/lib/plugins/subtitles/Subtitles.d.ts.map +1 -1
- package/lib/plugins/subtitles/Subtitles.js +131 -109
- package/package.json +1 -1
- package/src/plugins/bottom-gear/BottomGear.ts +26 -4
- package/src/plugins/clappr-nerd-stats/ClapprNerdStats.ts +4 -4
- package/src/plugins/level-selector/LevelSelector.ts +22 -19
- package/src/plugins/media-control/MediaControl.ts +43 -41
- package/src/plugins/source-controller/SourceController.ts +11 -1
- package/src/plugins/source-controller/__tests__/SourceController.test.ts +1 -1
- package/src/plugins/spinner-three-bounce/SpinnerThreeBounce.ts +46 -22
- package/src/plugins/subtitles/Subtitles.ts +146 -155
- package/temp/player.api.json +293 -822
- package/tsconfig.tsbuildinfo +1 -1
- package/docs/api/player.sourcecontroller.version.md +0 -14
- package/docs/api/player.spinnerthreebounce.attributes.md +0 -14
- package/docs/api/player.spinnerthreebounce.name.md +0 -11
- package/docs/api/player.spinnerthreebounce.render.md +0 -15
- package/docs/api/player.spinnerthreebounce.supportedversion.md +0 -13
- package/docs/api/player.subtitles.attributes.md +0 -14
- package/docs/api/player.subtitles.bindevents.md +0 -15
- package/docs/api/player.subtitles.buttonelement.md +0 -15
- package/docs/api/player.subtitles.events.md +0 -14
- package/docs/api/player.subtitles.name.md +0 -11
- package/docs/api/player.subtitles.preselectedlanguage.md +0 -11
- package/docs/api/player.subtitles.reload.md +0 -15
- package/docs/api/player.subtitles.render.md +0 -15
- package/docs/api/player.subtitles.selectsubtitles.md +0 -15
- package/docs/api/player.subtitles.startlevelswitch.md +0 -15
- package/docs/api/player.subtitles.stoplevelswitch.md +0 -15
- package/docs/api/player.subtitles.supportedversion.md +0 -13
- package/docs/api/player.subtitles.template.md +0 -11
- package/docs/api/player.subtitles.templatestring.md +0 -11
- package/docs/api/player.subtitles.unbindevents.md +0 -15
- package/docs/api/player.subtitles.version.md +0 -11
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Events, UICorePlugin, Browser, template, $, } from '@clappr/core';
|
|
2
|
-
import { reportError } from '@gcorevideo/utils';
|
|
2
|
+
import { reportError, trace } from '@gcorevideo/utils';
|
|
3
3
|
import assert from 'assert';
|
|
4
4
|
import { CLAPPR_VERSION } from '../../build.js';
|
|
5
5
|
import '../../../assets/subtitles/style.scss';
|
|
@@ -8,88 +8,102 @@ 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.js';
|
|
11
|
-
const VERSION = '
|
|
12
|
-
const LOCAL_STORAGE_SUBTITLES_ID = '
|
|
13
|
-
const T = 'plugins.
|
|
11
|
+
const VERSION = '2.19.14';
|
|
12
|
+
const LOCAL_STORAGE_SUBTITLES_ID = 'gplayer.plugins.subtitles.selected';
|
|
13
|
+
const T = 'plugins.subtitles';
|
|
14
14
|
const NO_TRACK = { language: 'off' };
|
|
15
|
+
/**
|
|
16
|
+
* A {@link MediaControl | media control} plugin that provides a UI to select the subtitles when available.
|
|
17
|
+
* @beta
|
|
18
|
+
*
|
|
19
|
+
* @remarks
|
|
20
|
+
* Depends on:
|
|
21
|
+
*
|
|
22
|
+
* - {@link MediaControl}
|
|
23
|
+
*
|
|
24
|
+
* Configuration options:
|
|
25
|
+
*
|
|
26
|
+
* - subtitles.language - The language of the subtitles to select by default.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```ts
|
|
30
|
+
* import { Subtitles } from '@gcorevideo/player'
|
|
31
|
+
*
|
|
32
|
+
* Player.registerPlugin(Subtitles)
|
|
33
|
+
*
|
|
34
|
+
* new Player({
|
|
35
|
+
* ...
|
|
36
|
+
* subtitles: {
|
|
37
|
+
* language: 'en',
|
|
38
|
+
* },
|
|
39
|
+
* })
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
15
42
|
export class Subtitles extends UICorePlugin {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
currentPlayback;
|
|
43
|
+
currentLevel = null;
|
|
44
|
+
isPreselectedApplied = false;
|
|
19
45
|
isShowing = false;
|
|
20
|
-
|
|
21
|
-
|
|
46
|
+
track = { ...NO_TRACK };
|
|
47
|
+
tracks = null;
|
|
48
|
+
$string = null;
|
|
49
|
+
/**
|
|
50
|
+
* @internal
|
|
51
|
+
*/
|
|
22
52
|
get name() {
|
|
23
|
-
return '
|
|
53
|
+
return 'subtitles';
|
|
24
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* @internal
|
|
57
|
+
*/
|
|
25
58
|
get supportedVersion() {
|
|
26
59
|
return { min: CLAPPR_VERSION };
|
|
27
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* @internal
|
|
63
|
+
*/
|
|
28
64
|
static get version() {
|
|
29
65
|
return VERSION;
|
|
30
66
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
67
|
+
static template = template(comboboxHTML);
|
|
68
|
+
static templateString = template(stringHTML);
|
|
69
|
+
/**
|
|
70
|
+
* @internal
|
|
71
|
+
*/
|
|
37
72
|
get attributes() {
|
|
38
73
|
return {
|
|
39
74
|
class: this.name,
|
|
40
75
|
'data-subtitles': '',
|
|
41
76
|
};
|
|
42
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* @internal
|
|
80
|
+
*/
|
|
43
81
|
get events() {
|
|
44
82
|
return {
|
|
45
83
|
'click [data-subtitles-select]': 'onLevelSelect',
|
|
46
84
|
'click [data-subtitles-button]': 'onShowLevelSelectMenu',
|
|
47
85
|
};
|
|
48
86
|
}
|
|
49
|
-
isPreselectedApplied = false;
|
|
50
|
-
track = { ...NO_TRACK };
|
|
51
87
|
get preselectedLanguage() {
|
|
52
88
|
return this.core.options.subtitles?.language ?? 'off';
|
|
53
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* @internal
|
|
92
|
+
*/
|
|
54
93
|
bindEvents() {
|
|
94
|
+
const mediaControl = this.core.getPlugin('media_control');
|
|
95
|
+
assert(mediaControl, 'media_control plugin is required');
|
|
55
96
|
this.listenTo(this.core, Events.CORE_RESIZE, this.playerResize);
|
|
56
|
-
this.
|
|
57
|
-
this.listenTo(
|
|
58
|
-
this.listenTo(
|
|
59
|
-
this.listenTo(this.core.mediaControl, Events.MEDIACONTROL_HIDE, this.hideSelectLevelMenu);
|
|
60
|
-
}
|
|
61
|
-
unBindEvents() {
|
|
62
|
-
// @ts-ignore
|
|
63
|
-
this.stopListening(this.core, Events.CORE_READY);
|
|
64
|
-
// @ts-ignore
|
|
65
|
-
this.stopListening(this.core.mediaControl, Events.MEDIACONTROL_CONTAINERCHANGED);
|
|
66
|
-
// @ts-ignore
|
|
67
|
-
this.stopListening(this.core.mediaControl, Events.MEDIACONTROL_RENDERED);
|
|
68
|
-
// @ts-ignore
|
|
69
|
-
this.stopListening(this.core.mediaControl, Events.MEDIACONTROL_HIDE);
|
|
70
|
-
// @ts-ignore
|
|
71
|
-
this.stopListening(this.core.mediaControl, Events.MEDIACONTROL_SHOW);
|
|
72
|
-
if (this.currentContainer) {
|
|
73
|
-
// @ts-ignore
|
|
74
|
-
this.stopListening(this.currentContainer, Events.CONTAINER_FULLSCREEN);
|
|
75
|
-
// @ts-ignore
|
|
76
|
-
this.stopListening(this.currentContainer, 'container:advertisement:start', this.onStartAd);
|
|
77
|
-
// @ts-ignore
|
|
78
|
-
this.stopListening(this.currentContainer, 'container:advertisement:finish', this.onFinishAd);
|
|
79
|
-
}
|
|
97
|
+
this.listenTo(this.core, Events.CORE_ACTIVE_CONTAINER_CHANGED, this.bindPlaybackEvents);
|
|
98
|
+
this.listenTo(mediaControl, Events.MEDIACONTROL_RENDERED, this.render);
|
|
99
|
+
this.listenTo(mediaControl, Events.MEDIACONTROL_HIDE, this.hideSelectLevelMenu);
|
|
80
100
|
}
|
|
81
101
|
bindPlaybackEvents() {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
this.currentPlayback = this.core.activePlayback;
|
|
87
|
-
this.currentContainer = this.core.activeContainer;
|
|
88
|
-
this.listenTo(this.currentContainer, Events.CONTAINER_FULLSCREEN, this.playerResize);
|
|
89
|
-
this.listenToOnce(this.currentPlayback, Events.PLAYBACK_PLAY, this.getTracks);
|
|
90
|
-
this.listenTo(this.currentContainer, 'container:advertisement:start', this.onStartAd);
|
|
102
|
+
this.listenTo(this.core.activeContainer, Events.CONTAINER_FULLSCREEN, this.playerResize);
|
|
103
|
+
this.listenToOnce(this.core.activePlayback, Events.PLAYBACK_PLAY, this.getTracks);
|
|
104
|
+
this.listenTo(this.core.activeContainer, 'container:advertisement:start', this.onStartAd);
|
|
91
105
|
// fix for iOS
|
|
92
|
-
const video = this.
|
|
106
|
+
const video = this.core.activePlayback.el;
|
|
93
107
|
assert(video, 'video element is required');
|
|
94
108
|
video.addEventListener('webkitbeginfullscreen', () => {
|
|
95
109
|
if (Browser.isiOS) {
|
|
@@ -103,10 +117,13 @@ export class Subtitles extends UICorePlugin {
|
|
|
103
117
|
});
|
|
104
118
|
}
|
|
105
119
|
getTracks() {
|
|
106
|
-
if (this.
|
|
120
|
+
if (this.core.activePlayback) {
|
|
107
121
|
try {
|
|
108
|
-
const tracks = this.
|
|
109
|
-
|
|
122
|
+
const tracks = this.core.activePlayback.el
|
|
123
|
+
.textTracks;
|
|
124
|
+
if (tracks.length > 0) {
|
|
125
|
+
this.setTracks(tracks);
|
|
126
|
+
}
|
|
110
127
|
}
|
|
111
128
|
catch (error) {
|
|
112
129
|
reportError(error);
|
|
@@ -114,23 +131,18 @@ export class Subtitles extends UICorePlugin {
|
|
|
114
131
|
}
|
|
115
132
|
}
|
|
116
133
|
onStartAd() {
|
|
117
|
-
if (this.isShowing && this.
|
|
134
|
+
if (this.isShowing && this.core.activeContainer) {
|
|
118
135
|
this.hide();
|
|
119
|
-
this.listenTo(this.
|
|
136
|
+
this.listenTo(this.core.activeContainer, 'container:advertisement:finish', this.onFinishAd);
|
|
120
137
|
}
|
|
121
138
|
}
|
|
122
139
|
onFinishAd() {
|
|
123
140
|
this.show();
|
|
124
|
-
this.stopListening(this.
|
|
125
|
-
}
|
|
126
|
-
reload() {
|
|
127
|
-
this.unBindEvents();
|
|
128
|
-
this.bindEvents();
|
|
129
|
-
this.bindPlaybackEvents();
|
|
141
|
+
this.stopListening(this.core.activeContainer, 'container:advertisement:finish', this.onFinishAd);
|
|
130
142
|
}
|
|
131
143
|
playerResize() {
|
|
132
|
-
const shouldShow = this.
|
|
133
|
-
isFullscreen(this.
|
|
144
|
+
const shouldShow = this.core.activeContainer &&
|
|
145
|
+
isFullscreen(this.core.activeContainer.el) &&
|
|
134
146
|
this.currentLevel &&
|
|
135
147
|
this.currentLevel.mode &&
|
|
136
148
|
Browser.isiOS &&
|
|
@@ -145,6 +157,9 @@ export class Subtitles extends UICorePlugin {
|
|
|
145
157
|
reportError(error);
|
|
146
158
|
}
|
|
147
159
|
}
|
|
160
|
+
/**
|
|
161
|
+
* Hides the subtitles menu and the subtitles.
|
|
162
|
+
*/
|
|
148
163
|
hide() {
|
|
149
164
|
this.isShowing = false;
|
|
150
165
|
this.renderIcon();
|
|
@@ -155,11 +170,14 @@ export class Subtitles extends UICorePlugin {
|
|
|
155
170
|
}
|
|
156
171
|
}
|
|
157
172
|
}
|
|
173
|
+
/**
|
|
174
|
+
* Shows the subtitles menu and the subtitles.
|
|
175
|
+
*/
|
|
158
176
|
show() {
|
|
159
177
|
this.isShowing = true;
|
|
160
178
|
this.renderIcon();
|
|
161
|
-
if (this.
|
|
162
|
-
isFullscreen(this.
|
|
179
|
+
if (this.core.activeContainer &&
|
|
180
|
+
isFullscreen(this.core.activeContainer.el) &&
|
|
163
181
|
this.currentLevel &&
|
|
164
182
|
this.currentLevel.mode &&
|
|
165
183
|
Browser.isiOS) {
|
|
@@ -171,59 +189,61 @@ export class Subtitles extends UICorePlugin {
|
|
|
171
189
|
}
|
|
172
190
|
}
|
|
173
191
|
shouldRender() {
|
|
174
|
-
|
|
175
|
-
return false;
|
|
176
|
-
}
|
|
177
|
-
if (!this.currentPlayback) {
|
|
178
|
-
return false;
|
|
179
|
-
}
|
|
180
|
-
// Only care if we have at least 2 to choose from
|
|
181
|
-
const hasLevels = !!(this.tracks && this.tracks.length > 0);
|
|
182
|
-
return hasLevels;
|
|
192
|
+
return !!(this.tracks && this.tracks.length > 0);
|
|
183
193
|
}
|
|
184
194
|
resizeFont() {
|
|
185
|
-
if (!this.
|
|
195
|
+
if (!this.core.activeContainer) {
|
|
186
196
|
return;
|
|
187
197
|
}
|
|
188
198
|
if (!this.$string) {
|
|
189
199
|
return;
|
|
190
200
|
}
|
|
191
|
-
const skinWidth = this.
|
|
201
|
+
const skinWidth = this.core.activeContainer.$el.width();
|
|
192
202
|
this.$string.find('p').css('font-size', skinWidth * 0.03);
|
|
193
203
|
}
|
|
204
|
+
/**
|
|
205
|
+
* @internal
|
|
206
|
+
*/
|
|
194
207
|
render() {
|
|
195
|
-
if (this.
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
this
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
208
|
+
if (!this.core.activeContainer) {
|
|
209
|
+
return this;
|
|
210
|
+
}
|
|
211
|
+
if (!this.shouldRender()) {
|
|
212
|
+
return this;
|
|
213
|
+
}
|
|
214
|
+
trace(`${T} render`, {
|
|
215
|
+
tracks: this.tracks?.length,
|
|
216
|
+
track: this.track?.language,
|
|
217
|
+
});
|
|
218
|
+
const mediaControl = this.core.getPlugin('media_control');
|
|
219
|
+
assert(mediaControl, 'media_control plugin is required');
|
|
220
|
+
this.$el.html(Subtitles.template({ tracks: this.tracks }));
|
|
221
|
+
this.core.activeContainer.$el.find('.subtitle-string').remove();
|
|
222
|
+
this.$string = $(Subtitles.templateString());
|
|
223
|
+
this.resizeFont();
|
|
224
|
+
this.core.activeContainer.$el.append(this.$string[0]);
|
|
225
|
+
const ss = mediaControl.getElement('subtitlesSelector');
|
|
226
|
+
if (ss && ss.length > 0) {
|
|
227
|
+
ss.append(this.el);
|
|
211
228
|
}
|
|
212
|
-
|
|
213
|
-
.
|
|
214
|
-
this.renderIcon();
|
|
229
|
+
else {
|
|
230
|
+
mediaControl.getRightPanel().append(this.el);
|
|
215
231
|
}
|
|
232
|
+
this.updateCurrentLevel(this.track);
|
|
233
|
+
this.highlightCurrentSubtitles();
|
|
234
|
+
this.applyPreselectedSubtitles();
|
|
235
|
+
this.renderIcon();
|
|
216
236
|
return this;
|
|
217
237
|
}
|
|
218
|
-
|
|
238
|
+
setTracks(tracks) {
|
|
219
239
|
this.tracks = tracks;
|
|
220
240
|
this.render();
|
|
221
241
|
}
|
|
222
242
|
findLevelBy(id) {
|
|
223
243
|
if (this.tracks) {
|
|
224
|
-
for (
|
|
225
|
-
if (
|
|
226
|
-
return
|
|
244
|
+
for (const track of this.tracks) {
|
|
245
|
+
if (track.language === id) {
|
|
246
|
+
return track; // TODO TrackInfo?
|
|
227
247
|
}
|
|
228
248
|
}
|
|
229
249
|
}
|
|
@@ -254,21 +274,21 @@ export class Subtitles extends UICorePlugin {
|
|
|
254
274
|
}
|
|
255
275
|
}
|
|
256
276
|
onShowLevelSelectMenu() {
|
|
277
|
+
trace(`${T} onShowLevelSelectMenu`);
|
|
257
278
|
this.toggleContextMenu();
|
|
258
279
|
}
|
|
259
280
|
hideSelectLevelMenu() {
|
|
260
281
|
;
|
|
261
|
-
this.$('
|
|
282
|
+
this.$('[data-subtitles] ul').hide();
|
|
262
283
|
}
|
|
263
284
|
toggleContextMenu() {
|
|
264
|
-
;
|
|
265
|
-
this.$('.subtitles ul').toggle();
|
|
285
|
+
this.$('[data-subtitles] ul').toggle();
|
|
266
286
|
}
|
|
267
287
|
buttonElement() {
|
|
268
|
-
return this.$('
|
|
288
|
+
return this.$('[data-subtitles] button');
|
|
269
289
|
}
|
|
270
290
|
levelElement(id) {
|
|
271
|
-
return this.$('
|
|
291
|
+
return this.$('[data-subtitles] ul a' + (id ? '[data-subtitles-select="' + id + '"]' : '')).parent();
|
|
272
292
|
}
|
|
273
293
|
startLevelSwitch() {
|
|
274
294
|
this.buttonElement().addClass('changing');
|
|
@@ -285,7 +305,7 @@ export class Subtitles extends UICorePlugin {
|
|
|
285
305
|
const track = this.tracks[i];
|
|
286
306
|
if (track.language === this.currentLevel.language) {
|
|
287
307
|
track.mode = 'showing';
|
|
288
|
-
const currentTime = this.
|
|
308
|
+
const currentTime = this.core.activePlayback?.getCurrentTime() ?? 0;
|
|
289
309
|
const cues = track.cues;
|
|
290
310
|
let subtitleText = '';
|
|
291
311
|
if (cues && cues.length) {
|
|
@@ -347,8 +367,10 @@ export class Subtitles extends UICorePlugin {
|
|
|
347
367
|
}
|
|
348
368
|
renderIcon() {
|
|
349
369
|
const icon = this.isShowing ? subtitlesOnIcon : subtitlesOffIcon;
|
|
350
|
-
this.core
|
|
351
|
-
.
|
|
370
|
+
this.core
|
|
371
|
+
.getPlugin('media_control')
|
|
372
|
+
.getElement('subtitlesSelector')
|
|
373
|
+
?.find('span.subtitle-text')
|
|
352
374
|
.html(icon);
|
|
353
375
|
}
|
|
354
376
|
}
|
package/package.json
CHANGED
|
@@ -13,9 +13,15 @@ import { ZeptoResult } from '../../utils/types.js';
|
|
|
13
13
|
|
|
14
14
|
const VERSION = '2.19.12';
|
|
15
15
|
|
|
16
|
-
const T = 'plugins.
|
|
16
|
+
const T = 'plugins.bottom_gear';
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Custom events emitted by the plugin
|
|
20
|
+
*/
|
|
21
|
+
export enum GearEvents {
|
|
22
|
+
/**
|
|
23
|
+
* Emitted when the gear menu is rendered
|
|
24
|
+
*/
|
|
19
25
|
MEDIACONTROL_GEAR_RENDERED = 'mediacontrol:gear:rendered',
|
|
20
26
|
}
|
|
21
27
|
|
|
@@ -30,6 +36,10 @@ export type GearItemElement = 'quality' | 'rate' | 'nerd';
|
|
|
30
36
|
* @beta
|
|
31
37
|
* @remarks
|
|
32
38
|
* The plugins provides a base for attaching custom settings UI in the gear menu
|
|
39
|
+
*
|
|
40
|
+
* Depends on:
|
|
41
|
+
*
|
|
42
|
+
* - {@link MediaControl | media_control}
|
|
33
43
|
*/
|
|
34
44
|
export class BottomGear extends UICorePlugin {
|
|
35
45
|
private isHd = false;
|
|
@@ -38,7 +48,7 @@ export class BottomGear extends UICorePlugin {
|
|
|
38
48
|
* @internal
|
|
39
49
|
*/
|
|
40
50
|
get name() {
|
|
41
|
-
return '
|
|
51
|
+
return 'bottom_gear';
|
|
42
52
|
}
|
|
43
53
|
|
|
44
54
|
/**
|
|
@@ -89,10 +99,22 @@ export class BottomGear extends UICorePlugin {
|
|
|
89
99
|
this.listenTo(mediaControl, ClapprEvents.MEDIACONTROL_HIDE, this.hide); // TODO mediacontrol show as well
|
|
90
100
|
}
|
|
91
101
|
|
|
102
|
+
/**
|
|
103
|
+
* @param name - Name of a gear menu placeholder item to attach custom UI
|
|
104
|
+
* @returns Zepto result of the element
|
|
105
|
+
*/
|
|
92
106
|
getElement(name: GearItemElement): ZeptoResult | null {
|
|
93
107
|
return this.core.getPlugin('media_control')?.getElement('gear')?.find(`.gear-options-list [data-${name}]`);
|
|
94
108
|
}
|
|
95
109
|
|
|
110
|
+
/**
|
|
111
|
+
* Replaces the content of the gear menu
|
|
112
|
+
* @param content - Zepto result of the element
|
|
113
|
+
*/
|
|
114
|
+
setContent(content: ZeptoResult) {
|
|
115
|
+
this.$el.find('.gear-wrapper').html(content);
|
|
116
|
+
}
|
|
117
|
+
|
|
96
118
|
private onActiveContainerChanged() {
|
|
97
119
|
trace(`${T} onActiveContainerChanged`);
|
|
98
120
|
this.bindContainerEvents();
|
|
@@ -131,7 +153,7 @@ export class BottomGear extends UICorePlugin {
|
|
|
131
153
|
|
|
132
154
|
mediaControl.getElement('gear')?.html(this.el);
|
|
133
155
|
this.core.trigger('gear:rendered'); // @deprecated
|
|
134
|
-
mediaControl.trigger(
|
|
156
|
+
mediaControl.trigger(GearEvents.MEDIACONTROL_GEAR_RENDERED);
|
|
135
157
|
return this;
|
|
136
158
|
}
|
|
137
159
|
|
|
@@ -21,7 +21,7 @@ import '../../../assets/clappr-nerd-stats/clappr-nerd-stats.scss';
|
|
|
21
21
|
import pluginHtml from '../../../assets/clappr-nerd-stats/clappr-nerd-stats.ejs';
|
|
22
22
|
import buttonHtml from '../../../assets/clappr-nerd-stats/button.ejs';
|
|
23
23
|
import statsIcon from '../../../assets/icons/new/stats.svg';
|
|
24
|
-
import { BottomGear,
|
|
24
|
+
import { BottomGear, GearEvents } from '../bottom-gear/BottomGear.js';
|
|
25
25
|
import { MediaControl } from '../media-control/MediaControl.js';
|
|
26
26
|
import assert from 'assert';
|
|
27
27
|
|
|
@@ -128,7 +128,7 @@ export class ClapprNerdStats extends UICorePlugin {
|
|
|
128
128
|
private iconPosition: IconPosition;
|
|
129
129
|
|
|
130
130
|
get name() {
|
|
131
|
-
return '
|
|
131
|
+
return 'nerd_stats';
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
get supportedVersion() {
|
|
@@ -186,7 +186,7 @@ export class ClapprNerdStats extends UICorePlugin {
|
|
|
186
186
|
const mediaControl = this.core.getPlugin('media_control') as MediaControl;
|
|
187
187
|
assert(mediaControl, 'media_control plugin is required');
|
|
188
188
|
this.listenToOnce(this.core, Events.CORE_READY, this.init);
|
|
189
|
-
this.listenTo(mediaControl,
|
|
189
|
+
this.listenTo(mediaControl, GearEvents.MEDIACONTROL_GEAR_RENDERED, this.addToBottomGear);
|
|
190
190
|
}
|
|
191
191
|
|
|
192
192
|
private init() {
|
|
@@ -316,7 +316,7 @@ export class ClapprNerdStats extends UICorePlugin {
|
|
|
316
316
|
}
|
|
317
317
|
|
|
318
318
|
private addToBottomGear() {
|
|
319
|
-
const gear = this.core.getPlugin('
|
|
319
|
+
const gear = this.core.getPlugin('bottom_gear') as BottomGear;
|
|
320
320
|
const $el = gear.getElement('nerd')
|
|
321
321
|
$el.html(buttonHtml)
|
|
322
322
|
const $button = $el.find('.nerd-button');
|
|
@@ -5,6 +5,7 @@ import { type QualityLevel } from '../../playback.types.js'
|
|
|
5
5
|
import { CLAPPR_VERSION } from '../../build.js'
|
|
6
6
|
import { ZeptoResult } from '../../utils/types.js'
|
|
7
7
|
import { TemplateFunction } from '../types.js'
|
|
8
|
+
import { BottomGear } from '../bottom-gear/BottomGear.js'
|
|
8
9
|
|
|
9
10
|
import buttonHtml from '../../../assets/level-selector/button.ejs'
|
|
10
11
|
import listHtml from '../../../assets/level-selector/list.ejs'
|
|
@@ -13,9 +14,10 @@ import arrowRightIcon from '../../../assets/icons/new/arrow-right.svg'
|
|
|
13
14
|
import arrowLeftIcon from '../../../assets/icons/new/arrow-left.svg'
|
|
14
15
|
import checkIcon from '../../../assets/icons/new/check.svg'
|
|
15
16
|
import '../../../assets/level-selector/style.scss'
|
|
17
|
+
import assert from 'assert'
|
|
16
18
|
|
|
17
19
|
|
|
18
|
-
const T = 'plugins.
|
|
20
|
+
const T = 'plugins.level_selector'
|
|
19
21
|
const VERSION = '2.19.4'
|
|
20
22
|
|
|
21
23
|
/**
|
|
@@ -23,7 +25,14 @@ const VERSION = '2.19.4'
|
|
|
23
25
|
* @beta
|
|
24
26
|
*
|
|
25
27
|
* @remarks
|
|
26
|
-
*
|
|
28
|
+
* Depends on:
|
|
29
|
+
*
|
|
30
|
+
* - {@link MediaControl}
|
|
31
|
+
*
|
|
32
|
+
* - {@link BottomGear}
|
|
33
|
+
*
|
|
34
|
+
* The plugin is rendered as an item in the gear menu.
|
|
35
|
+
*
|
|
27
36
|
* When clicked, it shows a list of quality levels to choose from.
|
|
28
37
|
*
|
|
29
38
|
* Configuration options:
|
|
@@ -53,15 +62,15 @@ export class LevelSelector extends UICorePlugin {
|
|
|
53
62
|
|
|
54
63
|
private isOpen = false
|
|
55
64
|
|
|
56
|
-
private buttonTemplate: TemplateFunction
|
|
65
|
+
private static readonly buttonTemplate: TemplateFunction = template(buttonHtml)
|
|
57
66
|
|
|
58
|
-
private listTemplate: TemplateFunction
|
|
67
|
+
private static readonly listTemplate: TemplateFunction = template(listHtml)
|
|
59
68
|
|
|
60
69
|
/**
|
|
61
70
|
* @internal
|
|
62
71
|
*/
|
|
63
72
|
get name() {
|
|
64
|
-
return '
|
|
73
|
+
return 'level_selector'
|
|
65
74
|
}
|
|
66
75
|
|
|
67
76
|
/**
|
|
@@ -183,6 +192,8 @@ export class LevelSelector extends UICorePlugin {
|
|
|
183
192
|
* @internal
|
|
184
193
|
*/
|
|
185
194
|
override render() {
|
|
195
|
+
assert(this.core.getPlugin('bottom_gear'), 'bottom_gear plugin is required')
|
|
196
|
+
|
|
186
197
|
if (!this.shouldRender()) {
|
|
187
198
|
return this
|
|
188
199
|
}
|
|
@@ -193,29 +204,21 @@ export class LevelSelector extends UICorePlugin {
|
|
|
193
204
|
}
|
|
194
205
|
|
|
195
206
|
private renderButton() {
|
|
196
|
-
if (!this.buttonTemplate) {
|
|
197
|
-
this.buttonTemplate = template(buttonHtml)
|
|
198
|
-
}
|
|
199
207
|
if (!this.isOpen) {
|
|
200
|
-
const html =
|
|
208
|
+
const html = LevelSelector.buttonTemplate({
|
|
201
209
|
arrowRightIcon,
|
|
202
210
|
currentText: this.currentText,
|
|
203
211
|
isHd: this.isHd,
|
|
204
212
|
hdIcon,
|
|
205
213
|
})
|
|
206
214
|
this.$el.html(html)
|
|
207
|
-
const
|
|
208
|
-
|
|
209
|
-
?.find('.gear-options-list [data-quality]')
|
|
210
|
-
?.html(this.el)
|
|
215
|
+
const gear = this.core.getPlugin('bottom_gear') as BottomGear
|
|
216
|
+
gear.getElement('quality')?.html(this.el)
|
|
211
217
|
}
|
|
212
218
|
}
|
|
213
219
|
|
|
214
220
|
private renderDropdown() {
|
|
215
|
-
|
|
216
|
-
this.listTemplate = template(listHtml)
|
|
217
|
-
}
|
|
218
|
-
const html = this.listTemplate!({
|
|
221
|
+
const html = LevelSelector.listTemplate({
|
|
219
222
|
arrowLeftIcon,
|
|
220
223
|
checkIcon,
|
|
221
224
|
labels: this.levelLabels,
|
|
@@ -224,8 +227,8 @@ export class LevelSelector extends UICorePlugin {
|
|
|
224
227
|
removeAuto: this.removeAuto,
|
|
225
228
|
})
|
|
226
229
|
this.$el.html(html)
|
|
227
|
-
const
|
|
228
|
-
|
|
230
|
+
const gear = this.core.getPlugin('bottom_gear') as BottomGear
|
|
231
|
+
gear?.setContent(this.el)
|
|
229
232
|
}
|
|
230
233
|
|
|
231
234
|
private get maxLevel() {
|