@eluvio/elv-player-js 1.0.136 → 1.0.138
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/README.md +20 -12
- package/package.json +4 -3
- package/src/Analytics.js +114 -0
- package/src/PlayerControls.js +195 -24
- package/src/index.js +295 -72
- package/src/static/icons/Icons.js +11 -8
- package/src/static/icons/media/list.svg +1 -0
- package/src/static/icons/media/next.svg +1 -0
- package/src/static/icons/media/previous.svg +1 -0
- package/src/static/stylesheets/player.scss +68 -6
- package/webpack.config.js +16 -7
- package/dist/5897e28fa3e8ac0a2fae.png +0 -0
- package/dist/bundle.333.7815f5ebcb1488f0e077.js +0 -2
- package/dist/bundle.333.7815f5ebcb1488f0e077.js.LICENSE.txt +0 -1
- package/dist/bundle.542.13fbfeeb92e41067e9da.js +0 -2
- package/dist/bundle.542.13fbfeeb92e41067e9da.js.LICENSE.txt +0 -13
- package/dist/bundle.543.f78d7c10787a91d4b582.js +0 -2
- package/dist/bundle.543.f78d7c10787a91d4b582.js.LICENSE.txt +0 -1
- package/dist/bundle.552.fbfc2e2fc68f6287f12c.js +0 -1
- package/dist/bundle.688.ef6032af9f304acb167f.js +0 -1
- package/dist/bundle.978.40fe2f1d0a843e187793.js +0 -1
- package/dist/index.js +0 -2
- package/dist/index.js.LICENSE.txt +0 -64
package/README.md
CHANGED
|
@@ -96,6 +96,7 @@ The library includes a helpful collection of configuration options in `EluvioPla
|
|
|
96
96
|
### Player Options
|
|
97
97
|
|
|
98
98
|
```javascript
|
|
99
|
+
// All player options and their defaults
|
|
99
100
|
playerOptions: {
|
|
100
101
|
controls: EluvioPlayerParameters.controls.AUTO_HIDE,
|
|
101
102
|
autoplay: EluvioPlayerParameters.autoplay.OFF,
|
|
@@ -103,11 +104,13 @@ The library includes a helpful collection of configuration options in `EluvioPla
|
|
|
103
104
|
loop: EluvioPlayerParameters.loop.OFF,
|
|
104
105
|
watermark: EluvioPlayerParameters.watermark.ON,
|
|
105
106
|
capLevelToPlayerSize: EluvioPlayerParameters.capLevelToPlayerSize.OFF,
|
|
107
|
+
collectVideoAnalytics: EluvioPlayerParameters.collectVideoAnalytics.ON,
|
|
106
108
|
posterUrl: undefined,
|
|
107
109
|
className: undefined,
|
|
108
110
|
controlsClassName: undefined,
|
|
109
111
|
hlsjsOptions: undefined,
|
|
110
112
|
dashjsOptions: undefined,
|
|
113
|
+
maxBitrate: undefined,
|
|
111
114
|
playerCallback: ({player, videoElement, hlsPlayer, dashPlayer, posterUrl}) => {},
|
|
112
115
|
errorCallback: (error, player) => {},
|
|
113
116
|
restartCallback: async (error) => {}
|
|
@@ -115,30 +118,35 @@ The library includes a helpful collection of configuration options in `EluvioPla
|
|
|
115
118
|
```
|
|
116
119
|
|
|
117
120
|
##### Values
|
|
118
|
-
* `controls` - How the controls should be displayed
|
|
121
|
+
* `controls` - How the controls should be displayed
|
|
122
|
+
* `AUTOHIDE (default)`: Player controls will be shown. Will automatically hide when not in use
|
|
119
123
|
* `ON`: Player controls will be shown
|
|
120
|
-
* `AUTOHIDE`: Player controls will be shown. Will automatically hide when not in use
|
|
121
124
|
* `DEFAULT`: Default HTML video controls will be shown
|
|
122
125
|
* `OFF`: No controls will be shown
|
|
123
126
|
* `OFF_WITH_VOLUME_TOGGLE`: No controls will be shown except a volume on/off toggle
|
|
124
|
-
* `autoplay` - Whether or not the video should autoplay.
|
|
127
|
+
* `autoplay` - Whether or not the video should autoplay. NOTE: Browsers may block autoplay video with audio
|
|
128
|
+
* `OFF (default)`: Video will not autoplay
|
|
125
129
|
* `ON`: Video will autoplay
|
|
126
|
-
* `OFF`: Video will not autoplay
|
|
127
130
|
* `WHEN_VISIBLE`: Video will autoplay only when the video element is visible, and will stop when the element is no longer visible
|
|
128
|
-
* `muted` - Whether or not the video will be muted.
|
|
131
|
+
* `muted` - Whether or not the video will be muted.
|
|
132
|
+
* `OFF (default)`: Video will not be muted
|
|
129
133
|
* `ON`: Video will be muted
|
|
130
|
-
* `OFF`: Video will not be muted
|
|
131
134
|
* `WHEN_NOT_VISIBLE`: Video will be muted when the video element is not visible
|
|
132
135
|
* `OFF_IF_POSSIBLE`: Video will not be muted unless playback is blocked due to audio (useful for autoplay)
|
|
133
|
-
* `loop` - Whether or not the video will loop.
|
|
136
|
+
* `loop` - Whether or not the video will loop.
|
|
137
|
+
* `OFF (default)` - Video will not loop
|
|
134
138
|
* `ON` - Video will loop
|
|
135
|
-
|
|
136
|
-
* `
|
|
137
|
-
* `ON` - Watermark will be shown
|
|
139
|
+
* `watermark`: Whether or not the Eluvio watermark will be shown.
|
|
140
|
+
* `ON (default)` - Watermark will be shown
|
|
138
141
|
* `OFF` - Watermark will not be shown
|
|
139
|
-
* `capLevelToPlayerSize`: Whether or not the playback quality should be limited by the size of the video element. Useful for reducing bandwidth usage for smaller video elements where a higher quality would not be beneficial.
|
|
142
|
+
* `capLevelToPlayerSize`: Whether or not the playback quality should be limited by the size of the video element. Useful for reducing bandwidth usage for smaller video elements where a higher quality would not be beneficial.
|
|
143
|
+
* `OFF (default)` - Playback quality will not be affected by the size of the video element (default)
|
|
140
144
|
* `ON` - Playback quality will be limited by the size of the video element
|
|
141
|
-
|
|
145
|
+
* `collectVideoAnalytics` - By default, the player will collect anonymized playback analytics to help improve the performance of the Eluvio Content Fabric.
|
|
146
|
+
* `ON (default)` - Player performance analytics will be collected
|
|
147
|
+
* `DISABLE_COOKIES`- Player performance analytics will be collected, but browser cookies will not be used
|
|
148
|
+
* `OFF` - Player performance analytics will not be collected
|
|
149
|
+
* `maxBitrate` - Maximum bitrate that the player will automatically use, in bits/second.
|
|
142
150
|
* `posterUrl` - Specify a URL for the poster image for the player
|
|
143
151
|
* `className` - HTML class to be added to the player
|
|
144
152
|
* `controlsClassName` - HTML class to be added to the player controls container
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eluvio/elv-player-js",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.138",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"license": "MIT",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"bump-version": "npm --git-tag-version --no-commit-hooks version patch",
|
|
10
10
|
"serve": "TEST_PAGE=true webpack-dev-server --hot --port 8089 --host=0.0.0.0",
|
|
11
11
|
"serve-example": "EXAMPLE_PAGE=true webpack-dev-server --hot --port 8089 --host=0.0.0.0",
|
|
12
|
-
"build": "node ./node_modules/webpack-cli/bin/cli.js --mode=production --devtool false",
|
|
12
|
+
"build": "BUILD_LIBRARY=true node ./node_modules/webpack-cli/bin/cli.js --mode=production --devtool false",
|
|
13
13
|
"build-test": "TEST_PAGE=true node ./node_modules/webpack-cli/bin/cli.js --mode=production --devtool false",
|
|
14
14
|
"build-example": "EXAMPLE_PAGE=true node ./node_modules/webpack-cli/bin/cli.js --mode=production --devtool false",
|
|
15
15
|
"build-analyze": "ANALYZE_BUNDLE=true node ./node_modules/webpack-cli/bin/cli.js --mode=production --devtool false",
|
|
@@ -36,11 +36,12 @@
|
|
|
36
36
|
"webpack.config.js"
|
|
37
37
|
],
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@eluvio/elv-client-js": "^4.0.
|
|
39
|
+
"@eluvio/elv-client-js": "^4.0.76",
|
|
40
40
|
"dashjs": "~4.7.0",
|
|
41
41
|
"focus-visible": "^5.2.0",
|
|
42
42
|
"hls.js": "~1.4.12",
|
|
43
43
|
"lodash": "^4.17.21",
|
|
44
|
+
"mux-embed": "^4.30.0",
|
|
44
45
|
"resize-observer-polyfill": "^1.5.1",
|
|
45
46
|
"url-join": "^4.0.1"
|
|
46
47
|
},
|
package/src/Analytics.js
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import Mux from "mux-embed";
|
|
2
|
+
const {version} = require("../package.json");
|
|
3
|
+
|
|
4
|
+
export const InitializeMuxMonitoring = async ({
|
|
5
|
+
appName="elv-player-js",
|
|
6
|
+
elvPlayer,
|
|
7
|
+
playoutUrl,
|
|
8
|
+
authorizationToken,
|
|
9
|
+
disableCookies
|
|
10
|
+
}) => {
|
|
11
|
+
playoutUrl = new URL(playoutUrl);
|
|
12
|
+
|
|
13
|
+
const client = await elvPlayer.Client();
|
|
14
|
+
const muxKey = (await client.NetworkInfo()).name === "main" ?
|
|
15
|
+
"aq4mdjn7qo5sbkf89pkvfv93j" :
|
|
16
|
+
"2i5480sms8vdgj0sv9bv6lpk5";
|
|
17
|
+
|
|
18
|
+
const versionHash = playoutUrl.pathname.split("/").find(token => token.startsWith("hq__"));
|
|
19
|
+
const objectId = client.utils.DecodeVersionHash(versionHash).objectId;
|
|
20
|
+
const offering = playoutUrl.toString().match(/\/rep\/playout\/([^/]+)/)[1] || "default";
|
|
21
|
+
const sessionId = playoutUrl.searchParams.get("sid");
|
|
22
|
+
|
|
23
|
+
let name = versionHash;
|
|
24
|
+
try {
|
|
25
|
+
const metadata = (await client.ContentObjectMetadata({
|
|
26
|
+
versionHash,
|
|
27
|
+
metadataSubtree: "/public",
|
|
28
|
+
select: [
|
|
29
|
+
"name",
|
|
30
|
+
"asset_metadata/display_title",
|
|
31
|
+
"asset_metadata/title"
|
|
32
|
+
],
|
|
33
|
+
authorizationToken
|
|
34
|
+
})) || {};
|
|
35
|
+
|
|
36
|
+
name =
|
|
37
|
+
(metadata.asset_metadata || {}).display_title ||
|
|
38
|
+
(metadata.asset_metadata || {}).title ||
|
|
39
|
+
metadata.name || versionHash;
|
|
40
|
+
// eslint-disable-next-line no-empty
|
|
41
|
+
} catch (error) {}
|
|
42
|
+
|
|
43
|
+
let tenantId = undefined;
|
|
44
|
+
try {
|
|
45
|
+
tenantId = await client.ContentObjectTenantId({versionHash});
|
|
46
|
+
// eslint-disable-next-line no-empty
|
|
47
|
+
} catch (error) {}
|
|
48
|
+
|
|
49
|
+
let address = await client.CurrentAccountAddress();
|
|
50
|
+
if(authorizationToken || client.staticToken) {
|
|
51
|
+
try {
|
|
52
|
+
const {payload} = client.utils.DecodeSignedToken(authorizationToken);
|
|
53
|
+
address = payload.adr || address;
|
|
54
|
+
// eslint-disable-next-line no-empty
|
|
55
|
+
} catch (error) {}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
let addressDigest = address;
|
|
59
|
+
if(typeof crypto !== "undefined") {
|
|
60
|
+
try {
|
|
61
|
+
const encoder = new TextEncoder();
|
|
62
|
+
addressDigest = Buffer.from(
|
|
63
|
+
await crypto.subtle.digest("SHA-256", encoder.encode(address))
|
|
64
|
+
).toString("hex");
|
|
65
|
+
// eslint-disable-next-line no-empty
|
|
66
|
+
} catch (error) {}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const options = {
|
|
70
|
+
debug: false,
|
|
71
|
+
disableCookies,
|
|
72
|
+
data: {
|
|
73
|
+
env_key: muxKey,
|
|
74
|
+
video_id: objectId,
|
|
75
|
+
video_variant_id: versionHash,
|
|
76
|
+
video_variant_name: offering,
|
|
77
|
+
video_title: name,
|
|
78
|
+
video_cdn: playoutUrl.hostname,
|
|
79
|
+
viewer_user_id: addressDigest,
|
|
80
|
+
sub_property_id: tenantId,
|
|
81
|
+
player_name: appName,
|
|
82
|
+
player_version: version,
|
|
83
|
+
player_init_time: elvPlayer.initTime
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
if(sessionId) {
|
|
88
|
+
options.data.view_session_id = sessionId;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if(elvPlayer.player) {
|
|
92
|
+
if(elvPlayer.HLS) {
|
|
93
|
+
options.hlsjs = elvPlayer.player;
|
|
94
|
+
options.Hls = elvPlayer.HLS;
|
|
95
|
+
} else if(elvPlayer.Dash) {
|
|
96
|
+
options.dashjs = elvPlayer.player;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
try {
|
|
100
|
+
Mux.monitor(elvPlayer.video, options);
|
|
101
|
+
|
|
102
|
+
// eslint-disable-next-line no-console
|
|
103
|
+
console.info("elv-player-js: Mux monitoring initialized");
|
|
104
|
+
// eslint-disable-next-line no-console
|
|
105
|
+
console.info(JSON.stringify({...options, hlsjs: {}}));
|
|
106
|
+
} catch (error) {
|
|
107
|
+
// eslint-disable-next-line no-console
|
|
108
|
+
console.warn("elv-player-js: Failed to initialize mux monitoring:");
|
|
109
|
+
// eslint-disable-next-line no-console
|
|
110
|
+
console.warn(JSON.stringify(options, null, 2));
|
|
111
|
+
// eslint-disable-next-line no-console
|
|
112
|
+
console.warn(error);
|
|
113
|
+
}
|
|
114
|
+
};
|
package/src/PlayerControls.js
CHANGED
|
@@ -10,7 +10,10 @@ import {
|
|
|
10
10
|
VolumeLowIcon,
|
|
11
11
|
VolumeHighIcon,
|
|
12
12
|
MultiViewIcon,
|
|
13
|
-
LeftArrowIcon
|
|
13
|
+
LeftArrowIcon,
|
|
14
|
+
PreviousTrackIcon,
|
|
15
|
+
NextTrackIcon,
|
|
16
|
+
CollectionIcon
|
|
14
17
|
} from "./static/icons/Icons";
|
|
15
18
|
// Icons are generated from .svg files to an importable JS file. To add a new icon, modify and run src/BuildIcons.js
|
|
16
19
|
|
|
@@ -123,7 +126,23 @@ const Time = (time, total) => {
|
|
|
123
126
|
return string;
|
|
124
127
|
};
|
|
125
128
|
|
|
126
|
-
export const InitializeTicketPrompt = (target, callback) => {
|
|
129
|
+
export const InitializeTicketPrompt = async (target, initialCode, callback) => {
|
|
130
|
+
// If initial code is provided, attempt to automatically redeem it before rendering the form
|
|
131
|
+
let initialError = "";
|
|
132
|
+
if(initialCode) {
|
|
133
|
+
try {
|
|
134
|
+
await callback(initialCode);
|
|
135
|
+
return;
|
|
136
|
+
} catch (error) {
|
|
137
|
+
// eslint-disable-next-line no-console
|
|
138
|
+
console.error("ELUVIO PLAYER: Invalid Code");
|
|
139
|
+
// eslint-disable-next-line no-console
|
|
140
|
+
console.error(error);
|
|
141
|
+
|
|
142
|
+
initialError = "Invalid Code";
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
127
146
|
const ticketModal = CreateElement({
|
|
128
147
|
parent: target,
|
|
129
148
|
type: "div",
|
|
@@ -144,6 +163,8 @@ export const InitializeTicketPrompt = (target, callback) => {
|
|
|
144
163
|
classes: ["eluvio-player__ticket-modal__form__error-text", "eluvio-player__ticket-modal__form__text"]
|
|
145
164
|
});
|
|
146
165
|
|
|
166
|
+
errorMessage.innerHTML = initialError;
|
|
167
|
+
|
|
147
168
|
const text = CreateElement({
|
|
148
169
|
parent: form,
|
|
149
170
|
type: "div",
|
|
@@ -158,6 +179,8 @@ export const InitializeTicketPrompt = (target, callback) => {
|
|
|
158
179
|
classes: ["eluvio-player__ticket-modal__form__input"]
|
|
159
180
|
});
|
|
160
181
|
|
|
182
|
+
input.value = initialCode;
|
|
183
|
+
|
|
161
184
|
const submit = CreateElement({
|
|
162
185
|
parent: form,
|
|
163
186
|
type: "button",
|
|
@@ -188,7 +211,8 @@ export const InitializeTicketPrompt = (target, callback) => {
|
|
|
188
211
|
};
|
|
189
212
|
|
|
190
213
|
class PlayerControls {
|
|
191
|
-
constructor({target, video, playerOptions, posterUrl, className}) {
|
|
214
|
+
constructor({player, target, video, playerOptions, posterUrl, className}) {
|
|
215
|
+
this.player = player;
|
|
192
216
|
this.target = target;
|
|
193
217
|
this.video = video;
|
|
194
218
|
this.playerOptions = playerOptions;
|
|
@@ -200,6 +224,8 @@ class PlayerControls {
|
|
|
200
224
|
this.SetPosterUrl(posterUrl);
|
|
201
225
|
}
|
|
202
226
|
|
|
227
|
+
this.HandleClickOutsideMenu = this.HandleClickOutsideMenu.bind(this);
|
|
228
|
+
|
|
203
229
|
this.InitializeControls(className);
|
|
204
230
|
}
|
|
205
231
|
|
|
@@ -267,7 +293,7 @@ class PlayerControls {
|
|
|
267
293
|
}
|
|
268
294
|
}
|
|
269
295
|
|
|
270
|
-
AutohideControls(controls) {
|
|
296
|
+
AutohideControls({controls, titleOnly=false}) {
|
|
271
297
|
this.video.addEventListener("play", () => {
|
|
272
298
|
this.played = true;
|
|
273
299
|
});
|
|
@@ -289,14 +315,14 @@ class PlayerControls {
|
|
|
289
315
|
const PlayerMove = () => {
|
|
290
316
|
this.FadeIn({
|
|
291
317
|
key: "controls",
|
|
292
|
-
elements: [controls, this.settingsMenu, this.toolTip],
|
|
318
|
+
elements: titleOnly ? [this.titleContainer] : [controls, this.settingsMenu, this.toolTip, this.titleContainer],
|
|
293
319
|
callback: () => {
|
|
294
320
|
this.target.classList.remove("-elv-no-cursor");
|
|
295
321
|
}
|
|
296
322
|
});
|
|
297
323
|
this.FadeOut({
|
|
298
324
|
key: "controls",
|
|
299
|
-
elements: [controls, this.settingsMenu, this.toolTip],
|
|
325
|
+
elements: titleOnly ? [this.titleContainer] : [controls, this.settingsMenu, this.toolTip, this.titleContainer],
|
|
300
326
|
delay: 3000,
|
|
301
327
|
unless: () => ControlsShouldShow(),
|
|
302
328
|
callback: () => {
|
|
@@ -350,7 +376,40 @@ class PlayerControls {
|
|
|
350
376
|
this.accountWatermark.innerText = address;
|
|
351
377
|
}
|
|
352
378
|
|
|
379
|
+
InitializeContentTitle({title, description}) {
|
|
380
|
+
if(!title && !description) { return; }
|
|
381
|
+
|
|
382
|
+
this.titleContainer = CreateElement({
|
|
383
|
+
parent: this.target,
|
|
384
|
+
type: "div",
|
|
385
|
+
classes: ["eluvio-player__title-container"],
|
|
386
|
+
prepend: true
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
if(title) {
|
|
390
|
+
const titleElement = CreateElement({
|
|
391
|
+
parent: this.titleContainer,
|
|
392
|
+
type: "div",
|
|
393
|
+
classes: ["eluvio-player__title"]
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
titleElement.innerHTML = title;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
if(description) {
|
|
400
|
+
const descriptionElement = CreateElement({
|
|
401
|
+
parent: this.titleContainer,
|
|
402
|
+
type: "div",
|
|
403
|
+
classes: ["eluvio-player__description"]
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
descriptionElement.innerHTML = description;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
353
410
|
InitializeControls(className="") {
|
|
411
|
+
const collectionInfo = this.player.collectionInfo;
|
|
412
|
+
|
|
354
413
|
this.target.setAttribute("tabindex", "0");
|
|
355
414
|
|
|
356
415
|
if(this.playerOptions.watermark) {
|
|
@@ -434,7 +493,7 @@ class PlayerControls {
|
|
|
434
493
|
volumeButton.innerHTML = this.video.muted || this.video.volume === 0 ? MutedIcon : (this.video.volume < 0.5 ? VolumeLowIcon : VolumeHighIcon);
|
|
435
494
|
});
|
|
436
495
|
|
|
437
|
-
this.AutohideControls(controls);
|
|
496
|
+
this.AutohideControls({controls, titleOnly: false});
|
|
438
497
|
};
|
|
439
498
|
|
|
440
499
|
const HasAudio = () => (this.video.mozHasAudio || Boolean(this.video.webkitAudioDecodedByteCount) || Boolean(this.video.audioTracks && this.video.audioTracks.length));
|
|
@@ -559,6 +618,21 @@ class PlayerControls {
|
|
|
559
618
|
volumeBar.value = volumeSlider.value;
|
|
560
619
|
});
|
|
561
620
|
|
|
621
|
+
// Collection previous track
|
|
622
|
+
if(collectionInfo && collectionInfo.isPlaylist) {
|
|
623
|
+
const collectionPreviousButton = CreateImageButton({
|
|
624
|
+
parent: controls,
|
|
625
|
+
svg: PreviousTrackIcon,
|
|
626
|
+
classes: ["eluvio-player__controls__previous-track"],
|
|
627
|
+
label: "Previous Track",
|
|
628
|
+
options: {
|
|
629
|
+
disabled: collectionInfo.mediaIndex === 0
|
|
630
|
+
}
|
|
631
|
+
});
|
|
632
|
+
|
|
633
|
+
collectionPreviousButton.addEventListener("click", () => this.player.CollectionPlayPrevious());
|
|
634
|
+
}
|
|
635
|
+
|
|
562
636
|
const progressTime = CreateElement({
|
|
563
637
|
parent: controls,
|
|
564
638
|
type: "div",
|
|
@@ -644,6 +718,36 @@ class PlayerControls {
|
|
|
644
718
|
|
|
645
719
|
totalTime.innerHTML = "00:00";
|
|
646
720
|
|
|
721
|
+
// Collection previous track
|
|
722
|
+
if(collectionInfo && collectionInfo.isPlaylist) {
|
|
723
|
+
const collectionNextButton = CreateImageButton({
|
|
724
|
+
parent: controls,
|
|
725
|
+
svg: NextTrackIcon,
|
|
726
|
+
classes: ["eluvio-player__controls__next-track"],
|
|
727
|
+
label: "Next Track",
|
|
728
|
+
options: {
|
|
729
|
+
disabled: collectionInfo.mediaIndex >= collectionInfo.mediaLength - 1
|
|
730
|
+
}
|
|
731
|
+
});
|
|
732
|
+
|
|
733
|
+
collectionNextButton.addEventListener("click", () => this.player.CollectionPlayNext());
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
if(collectionInfo) {
|
|
737
|
+
this.collectionButton = CreateImageButton({
|
|
738
|
+
parent: controls,
|
|
739
|
+
svg: CollectionIcon,
|
|
740
|
+
classes: ["eluvio-player__controls__collection"],
|
|
741
|
+
label: "Collection Info"
|
|
742
|
+
});
|
|
743
|
+
|
|
744
|
+
this.collectionButton.addEventListener("click", () => {
|
|
745
|
+
this.settingsMenu.dataset.mode === "collection" ?
|
|
746
|
+
this.HideSettingsMenu() :
|
|
747
|
+
this.ShowCollectionMenu();
|
|
748
|
+
});
|
|
749
|
+
}
|
|
750
|
+
|
|
647
751
|
// Right buttons container
|
|
648
752
|
this.rightButtonsContainer = CreateElement({
|
|
649
753
|
parent: controls,
|
|
@@ -651,6 +755,20 @@ class PlayerControls {
|
|
|
651
755
|
classes: ["eluvio-player__controls__right-buttons"]
|
|
652
756
|
});
|
|
653
757
|
|
|
758
|
+
this.settingsButton = CreateImageButton({
|
|
759
|
+
parent: this.rightButtonsContainer,
|
|
760
|
+
svg: SettingsIcon,
|
|
761
|
+
classes: ["eluvio-player__controls__button-settings"],
|
|
762
|
+
prepend: true,
|
|
763
|
+
label: "Settings"
|
|
764
|
+
});
|
|
765
|
+
|
|
766
|
+
this.settingsButton.addEventListener("click", () => {
|
|
767
|
+
this.settingsMenu.dataset.mode.startsWith("settings") ?
|
|
768
|
+
this.HideSettingsMenu() :
|
|
769
|
+
this.ShowSettingsMenu();
|
|
770
|
+
});
|
|
771
|
+
|
|
654
772
|
// Fullscreen
|
|
655
773
|
const fullscreenButton = CreateImageButton({
|
|
656
774
|
parent: this.rightButtonsContainer,
|
|
@@ -805,9 +923,7 @@ class PlayerControls {
|
|
|
805
923
|
}
|
|
806
924
|
});
|
|
807
925
|
|
|
808
|
-
|
|
809
|
-
this.AutohideControls(controls);
|
|
810
|
-
}
|
|
926
|
+
this.AutohideControls({controls, titleOnly: this.playerOptions.controls !== EluvioPlayerParameters.controls.AUTO_HIDE});
|
|
811
927
|
}
|
|
812
928
|
|
|
813
929
|
ShowHLSOptionsForm({hlsOptions={}, SetPlayerProfile, hlsVersion}) {
|
|
@@ -935,7 +1051,14 @@ class PlayerControls {
|
|
|
935
1051
|
this.hlsOptionsFormContainer && this.hlsOptionsFormContainer.remove();
|
|
936
1052
|
}
|
|
937
1053
|
|
|
1054
|
+
HandleClickOutsideMenu(event) {
|
|
1055
|
+
if(!this.settingsMenu.contains(event.target)) {
|
|
1056
|
+
this.HideSettingsMenu();
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
|
|
938
1060
|
InitializeMenu(mode) {
|
|
1061
|
+
this.HideSettingsMenu();
|
|
939
1062
|
this.settingsMenu.innerHTML = "";
|
|
940
1063
|
this.settingsMenu.classList.remove("eluvio-player__controls__settings-menu-hidden");
|
|
941
1064
|
this.settingsMenu.setAttribute("data-mode", mode);
|
|
@@ -949,6 +1072,16 @@ class PlayerControls {
|
|
|
949
1072
|
});
|
|
950
1073
|
|
|
951
1074
|
closeButton.addEventListener("click", () => this.HideSettingsMenu());
|
|
1075
|
+
|
|
1076
|
+
setTimeout(() => {
|
|
1077
|
+
document.addEventListener("click", this.HandleClickOutsideMenu);
|
|
1078
|
+
}, 100);
|
|
1079
|
+
|
|
1080
|
+
if(mode === "collection") {
|
|
1081
|
+
this.collectionButton.classList.add("eluvio-player__controls__button--active");
|
|
1082
|
+
} else if(mode.includes("setting")) {
|
|
1083
|
+
this.settingsButton.classList.add("eluvio-player__controls__button--active");
|
|
1084
|
+
}
|
|
952
1085
|
}
|
|
953
1086
|
|
|
954
1087
|
AddSetting({Retrieve, Set}) {
|
|
@@ -1044,37 +1177,73 @@ class PlayerControls {
|
|
|
1044
1177
|
}
|
|
1045
1178
|
|
|
1046
1179
|
HideSettingsMenu() {
|
|
1180
|
+
document.removeEventListener("click", this.HandleClickOutsideMenu);
|
|
1181
|
+
|
|
1047
1182
|
const mode = this.settingsMenu.dataset.mode;
|
|
1048
1183
|
if(mode === "settings") {
|
|
1049
1184
|
this.settingsButton.focus();
|
|
1050
1185
|
} else if(mode === "multiview") {
|
|
1051
1186
|
this.multiviewButton.focus();
|
|
1187
|
+
} else if(mode === "collection") {
|
|
1188
|
+
this.collectionButton.focus();
|
|
1052
1189
|
}
|
|
1053
1190
|
|
|
1054
1191
|
this.settingsMenu.innerHTML = "";
|
|
1055
1192
|
this.settingsMenu.classList.add("eluvio-player__controls__settings-menu-hidden");
|
|
1056
1193
|
this.settingsMenu.setAttribute("data-mode", "hidden");
|
|
1194
|
+
|
|
1195
|
+
this.settingsButton.classList.remove("eluvio-player__controls__button--active");
|
|
1196
|
+
this.collectionButton && this.collectionButton.classList.remove("eluvio-player__controls__button--active");
|
|
1197
|
+
this.multiviewButton && this.multiviewButton.classList.remove("eluvio-player__controls__button--active");
|
|
1057
1198
|
}
|
|
1058
1199
|
|
|
1200
|
+
// Settings were updated - if the menu is already open, force it to refresh
|
|
1059
1201
|
UpdateSettings() {
|
|
1060
|
-
if(
|
|
1061
|
-
this.
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
classes: ["eluvio-player__controls__button-settings"],
|
|
1065
|
-
prepend: true,
|
|
1066
|
-
label: "Settings"
|
|
1067
|
-
});
|
|
1202
|
+
if(this.settingsMenu.dataset.mode === "settings") {
|
|
1203
|
+
this.ShowSettingsMenu();
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1068
1206
|
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1207
|
+
ShowCollectionMenu() {
|
|
1208
|
+
if(
|
|
1209
|
+
!this.player.collectionInfo ||
|
|
1210
|
+
!this.player.collectionInfo.content ||
|
|
1211
|
+
this.player.collectionInfo.content.length <= 1
|
|
1212
|
+
) {
|
|
1213
|
+
return;
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
this.InitializeMenu("collection");
|
|
1217
|
+
|
|
1218
|
+
const collectionTitle = CreateElement({
|
|
1219
|
+
parent: this.settingsMenu,
|
|
1220
|
+
type: "div",
|
|
1221
|
+
classes: ["eluvio-player__controls__settings-menu__title"]
|
|
1222
|
+
});
|
|
1223
|
+
|
|
1224
|
+
collectionTitle.innerHTML = this.player.collectionInfo.title;
|
|
1225
|
+
|
|
1226
|
+
this.player.collectionInfo.content
|
|
1227
|
+
.forEach((option, index) => {
|
|
1228
|
+
const active = this.player.collectionInfo.mediaIndex === index;
|
|
1229
|
+
const optionButton = CreateElement({
|
|
1230
|
+
parent: this.settingsMenu,
|
|
1231
|
+
type: "button",
|
|
1232
|
+
classes: ["eluvio-player__controls__settings-menu__option", active ? "eluvio-player__controls__settings-menu__option-selected" : ""]
|
|
1233
|
+
});
|
|
1234
|
+
|
|
1235
|
+
optionButton.innerHTML = option.title || option.mediaHash;
|
|
1236
|
+
|
|
1237
|
+
optionButton.addEventListener("click", () => {
|
|
1238
|
+
this.player.CollectionPlay({mediaIndex: index});
|
|
1072
1239
|
this.HideSettingsMenu();
|
|
1240
|
+
});
|
|
1073
1241
|
});
|
|
1074
|
-
}
|
|
1075
1242
|
|
|
1076
|
-
|
|
1077
|
-
|
|
1243
|
+
// Focus on first element in list when menu opened
|
|
1244
|
+
const firstItem = this.settingsMenu.querySelector("button");
|
|
1245
|
+
if(firstItem) {
|
|
1246
|
+
firstItem.focus();
|
|
1078
1247
|
}
|
|
1079
1248
|
}
|
|
1080
1249
|
|
|
@@ -1174,6 +1343,8 @@ class PlayerControls {
|
|
|
1174
1343
|
return;
|
|
1175
1344
|
}
|
|
1176
1345
|
|
|
1346
|
+
this.multiviewButton.classList.add("eluvio-player__controls__button--active");
|
|
1347
|
+
|
|
1177
1348
|
this.settingsMenu.setAttribute("data-mode", "multiview");
|
|
1178
1349
|
this.settingsMenu.classList.remove("eluvio-player__controls__settings-menu-hidden");
|
|
1179
1350
|
|