jekyll-theme-conference 3.4.1 → 3.5.0
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.
- checksums.yaml +4 -4
- data/README.md +16 -8
- data/_includes/js/conference.js +26 -16
- data/_includes/js/init.js +37 -0
- data/_includes/js/{bootstrap.js → lib/bootstrap.js} +0 -0
- data/_includes/js/{jquery-3.5.1.min.js → lib/jquery-3.5.1.min.js} +0 -0
- data/_includes/js/{leaflet-easybutton.js → lib/leaflet-easybutton.js} +0 -0
- data/_includes/js/{leaflet-locatecontrol.js → lib/leaflet-locatecontrol.js} +0 -0
- data/_includes/js/{leaflet-providers.js → lib/leaflet-providers.js} +0 -0
- data/_includes/js/{leaflet.js → lib/leaflet.js} +0 -0
- data/_includes/js/{popper.min.js → lib/popper.min.js} +0 -0
- data/_includes/js/{syncscroll.js → lib/syncscroll.js} +0 -0
- data/_includes/js/live.js +718 -0
- data/_includes/js/map.js +38 -0
- data/_includes/js/{conference-modal.js → modal.js} +13 -15
- data/_includes/js/{conference-program.js → program.js} +10 -17
- data/_includes/partials/footer.html +1 -1
- data/_includes/partials/get_live_timestamps.html +1 -1
- data/_includes/partials/header.html +1 -1
- data/_includes/partials/navbar.html +1 -1
- data/_includes/partials/show_live_button.html +2 -2
- data/_layouts/config.html +78 -0
- data/_layouts/data.html +3 -2
- data/_layouts/home.html +1 -1
- data/assets/js/config.json +3 -0
- metadata +17 -14
- data/_includes/js/conference-live.js +0 -720
- data/_includes/js/conference-map.js +0 -45
@@ -0,0 +1,718 @@
|
|
1
|
+
window.conference.live = (() => {
|
2
|
+
let config;
|
3
|
+
let lang;
|
4
|
+
|
5
|
+
let data;
|
6
|
+
|
7
|
+
let confStart;
|
8
|
+
let confEnd;
|
9
|
+
let confDur;
|
10
|
+
|
11
|
+
let stream;
|
12
|
+
let streamPause;
|
13
|
+
let streamPrepend;
|
14
|
+
let streamExtend;
|
15
|
+
|
16
|
+
let demo;
|
17
|
+
let demoStart;
|
18
|
+
let demoEnd;
|
19
|
+
let demoDur;
|
20
|
+
let demoPause;
|
21
|
+
|
22
|
+
let freezeTime = false;
|
23
|
+
let timeFrozen = 0;
|
24
|
+
let timeOffset = 0;
|
25
|
+
|
26
|
+
let liveTimer;
|
27
|
+
let streamVideoTimer;
|
28
|
+
let streamInfoTimer;
|
29
|
+
|
30
|
+
const loadData = () => {
|
31
|
+
// Load schedule
|
32
|
+
const request = new Request(window.conference.config.baseurl + '/assets/js/data.json');
|
33
|
+
|
34
|
+
fetch(request)
|
35
|
+
.then(response =>
|
36
|
+
response.json()
|
37
|
+
)
|
38
|
+
.then(d => {
|
39
|
+
data = d;
|
40
|
+
})
|
41
|
+
.catch((error) => {
|
42
|
+
console.log(error);
|
43
|
+
});
|
44
|
+
};
|
45
|
+
|
46
|
+
const getData = () => {
|
47
|
+
// Return data
|
48
|
+
return data;
|
49
|
+
};
|
50
|
+
|
51
|
+
const mod = (n, m) => {
|
52
|
+
// Absolute modulo
|
53
|
+
return ((n % m) + m) % m;
|
54
|
+
};
|
55
|
+
|
56
|
+
const timeNow = () => {
|
57
|
+
// Current timestamp in seconds
|
58
|
+
return Math.floor(Date.now() / 1000);
|
59
|
+
};
|
60
|
+
|
61
|
+
const timeCont = () => {
|
62
|
+
// Continuous time (respecting previous pauses)
|
63
|
+
return timeNow() - timeOffset;
|
64
|
+
};
|
65
|
+
|
66
|
+
const timeCycle = () => {
|
67
|
+
// Cyclic timestamp in seconds
|
68
|
+
const actTime = timeNow();
|
69
|
+
const relTime = mod(actTime, demoDur + 2*demoPause) / (demoDur + 2*demoPause);
|
70
|
+
const cycleTime = mod((demoEnd - demoStart) * relTime - timeOffset, (demoEnd - demoStart)) + demoStart;
|
71
|
+
return cycleTime;
|
72
|
+
};
|
73
|
+
|
74
|
+
const time = () => {
|
75
|
+
// Return app time
|
76
|
+
if (freezeTime) {
|
77
|
+
return timeFrozen;
|
78
|
+
}
|
79
|
+
else if (demo) {
|
80
|
+
return timeCycle();
|
81
|
+
}
|
82
|
+
else {
|
83
|
+
return timeCont();
|
84
|
+
}
|
85
|
+
};
|
86
|
+
|
87
|
+
const pauseTime = () => {
|
88
|
+
// Pause app time
|
89
|
+
if (!freezeTime) {
|
90
|
+
timeFrozen = time();
|
91
|
+
freezeTime = true;
|
92
|
+
|
93
|
+
stopUpdate();
|
94
|
+
}
|
95
|
+
};
|
96
|
+
|
97
|
+
const continueTime = () => {
|
98
|
+
// Continue app time
|
99
|
+
if (freezeTime) {
|
100
|
+
freezeTime = false;
|
101
|
+
timeOffset += time() - timeFrozen;
|
102
|
+
startUpdate();
|
103
|
+
}
|
104
|
+
};
|
105
|
+
|
106
|
+
const resetTime = () => {
|
107
|
+
// Reset app time
|
108
|
+
timeOffset = 0;
|
109
|
+
freezeTime = false;
|
110
|
+
|
111
|
+
startUpdate();
|
112
|
+
};
|
113
|
+
|
114
|
+
const setTime = (newTime, newDay) => {
|
115
|
+
// Set and pause app time
|
116
|
+
pauseTime();
|
117
|
+
|
118
|
+
let dayIdx;
|
119
|
+
if (!newDay) {
|
120
|
+
dayIdx = 0;
|
121
|
+
}
|
122
|
+
else if (Number.isInteger(newDay)) {
|
123
|
+
dayIdx = newDay-1;
|
124
|
+
}
|
125
|
+
else if (/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/.test(newDay)) {
|
126
|
+
dayIdx = data.days.find(o => o.name === newDay);
|
127
|
+
}
|
128
|
+
else {
|
129
|
+
dayIdx = data.days.find(o => o.name === newDay);
|
130
|
+
}
|
131
|
+
const newDate = data.days[dayIdx].date;
|
132
|
+
|
133
|
+
let d = new Date(newDate);
|
134
|
+
newTime = newTime.split(':');
|
135
|
+
d.setHours(newTime[0], newTime[1]);
|
136
|
+
|
137
|
+
timeFrozen = Math.floor(d.getTime() / 1000);
|
138
|
+
|
139
|
+
update();
|
140
|
+
};
|
141
|
+
|
142
|
+
const getTime = () => {
|
143
|
+
// Return app time as string
|
144
|
+
const tConvert = time();
|
145
|
+
|
146
|
+
const d = new Date(tConvert * 1000);
|
147
|
+
const dStr = d.toISOString().slice(0,10);
|
148
|
+
const h = d.getHours();
|
149
|
+
const m = d.getMinutes();
|
150
|
+
|
151
|
+
return dStr +" "+ h +":"+ (m < 10 ? "0" : "") + m;
|
152
|
+
};
|
153
|
+
|
154
|
+
const timeUnit = () => {
|
155
|
+
// App time refresh rate
|
156
|
+
if (demo) {
|
157
|
+
return 0.1;
|
158
|
+
}
|
159
|
+
else {
|
160
|
+
return 60;
|
161
|
+
}
|
162
|
+
};
|
163
|
+
|
164
|
+
const delayStart = (startTime) => {
|
165
|
+
// Seconds until given startTime occurs
|
166
|
+
const tNow = time();
|
167
|
+
const tUnit = timeUnit();
|
168
|
+
|
169
|
+
if (demo) {
|
170
|
+
// Convert virtual duration to real duration
|
171
|
+
return mod(startTime - tNow, demoEnd - demoStart) / (demoEnd - demoStart) * (demoDur + 2*demoPause);
|
172
|
+
}
|
173
|
+
else {
|
174
|
+
if (startTime > tNow) {
|
175
|
+
return startTime - tNow;
|
176
|
+
}
|
177
|
+
else {
|
178
|
+
// Start on the unit
|
179
|
+
return (tUnit - (tNow % tUnit));
|
180
|
+
}
|
181
|
+
}
|
182
|
+
};
|
183
|
+
|
184
|
+
const model = {
|
185
|
+
set demo(value) {
|
186
|
+
demo = value;
|
187
|
+
resetTime();
|
188
|
+
},
|
189
|
+
get demo() {
|
190
|
+
return demo;
|
191
|
+
}
|
192
|
+
};
|
193
|
+
|
194
|
+
const updateLive = () => {
|
195
|
+
// Update status all live elements in DOM
|
196
|
+
const tNow = time();
|
197
|
+
const liveShow = document.getElementsByClassName('live-show');
|
198
|
+
const liveHide = document.getElementsByClassName('live-hide');
|
199
|
+
const liveTime = document.getElementsByClassName('live-time');
|
200
|
+
const livePast = document.getElementsByClassName('live-past');
|
201
|
+
|
202
|
+
// Show elements for a given period
|
203
|
+
for (let i = 0; i < liveShow.length; i++) {
|
204
|
+
const tStarts = liveShow[i].dataset.start.split(',');
|
205
|
+
const tEnds = liveShow[i].dataset.end.split(',');
|
206
|
+
|
207
|
+
for (let k = 0; k < tStarts.length; k++) {
|
208
|
+
if (tNow >= tStarts[k] && tNow < tEnds[k]) {
|
209
|
+
// Show when active
|
210
|
+
liveShow[i].classList.remove('d-none');
|
211
|
+
break;
|
212
|
+
}
|
213
|
+
else if (!liveShow[i].classList.contains('d-none')) {
|
214
|
+
// Hide otherwise
|
215
|
+
liveShow[i].classList.add('d-none');
|
216
|
+
}
|
217
|
+
}
|
218
|
+
}
|
219
|
+
|
220
|
+
// Hide elements for a given period
|
221
|
+
for (let i = 0; i < liveHide.length; i++) {
|
222
|
+
const tStarts = liveHide[i].dataset.start.split(',');
|
223
|
+
const tEnds = liveHide[i].dataset.end.split(',');
|
224
|
+
|
225
|
+
for (let k = 0; k < tStarts.length; k++) {
|
226
|
+
if (tNow >= tStarts[k] && tNow < tEnds[k]) {
|
227
|
+
// Hide when active
|
228
|
+
if (!liveHide[i].classList.contains('d-none')) {
|
229
|
+
liveHide[i].classList.add('d-none');
|
230
|
+
break;
|
231
|
+
}
|
232
|
+
}
|
233
|
+
else {
|
234
|
+
// Show otherwise
|
235
|
+
liveHide[i].classList.remove('d-none');
|
236
|
+
}
|
237
|
+
}
|
238
|
+
}
|
239
|
+
|
240
|
+
// Update duration string for given elements
|
241
|
+
for (let i = 0; i < liveTime.length; i++) {
|
242
|
+
const t = liveTime[i].dataset.time;
|
243
|
+
if (typeof t == "undefined") {
|
244
|
+
break;
|
245
|
+
}
|
246
|
+
let tRel = tNow - t;
|
247
|
+
|
248
|
+
let tStr;
|
249
|
+
if (tRel >= -60 && tRel < 0) {
|
250
|
+
tStr = lang.time.soon;
|
251
|
+
}
|
252
|
+
else if (tRel >= 0 && tRel < 60) {
|
253
|
+
tStr = lang.time.now;
|
254
|
+
}
|
255
|
+
else {
|
256
|
+
if (tRel < 0) {
|
257
|
+
tStr = lang.time.in;
|
258
|
+
}
|
259
|
+
else {
|
260
|
+
tStr = lang.time.since;
|
261
|
+
}
|
262
|
+
tRel = Math.abs(tRel);
|
263
|
+
|
264
|
+
let dWeeks = Math.floor(tRel / (7*24*60*60));
|
265
|
+
let dDays = Math.floor(tRel / (24*60*60));
|
266
|
+
let dHours = Math.floor(tRel / (60*60));
|
267
|
+
let dMins = Math.floor(tRel / (60));
|
268
|
+
if (dWeeks > 4) {
|
269
|
+
break;
|
270
|
+
}
|
271
|
+
else if (dWeeks > 1) {
|
272
|
+
tStr += dWeeks +' '+ lang.time.weeks;
|
273
|
+
}
|
274
|
+
else if (dWeeks == 1) {
|
275
|
+
tStr += '1 '+ lang.time.week;
|
276
|
+
}
|
277
|
+
else if (dDays > 1) {
|
278
|
+
tStr += dDays +' '+ lang.time.days;
|
279
|
+
}
|
280
|
+
else if (dDays == 1) {
|
281
|
+
tStr += '1 '+ lang.time.day;
|
282
|
+
}
|
283
|
+
else if (dHours > 1) {
|
284
|
+
tStr += dHours +' '+ lang.time.hours;
|
285
|
+
}
|
286
|
+
else if (dHours == 1) {
|
287
|
+
tStr += '1 '+ lang.time.hour;
|
288
|
+
}
|
289
|
+
else if (dMins > 1) {
|
290
|
+
tStr += dMins +' '+ lang.time.minutes;
|
291
|
+
}
|
292
|
+
else {
|
293
|
+
tStr += '1 '+ lang.time.minute;
|
294
|
+
}
|
295
|
+
}
|
296
|
+
|
297
|
+
liveTime[i].innerHTML = tStr;
|
298
|
+
}
|
299
|
+
|
300
|
+
// Disable elements for a given period
|
301
|
+
for (let i = 0; i < livePast.length; i++) {
|
302
|
+
const t = livePast[i].dataset.time;
|
303
|
+
if (typeof t == "undefined") {
|
304
|
+
break;
|
305
|
+
}
|
306
|
+
let tRel = tNow - t;
|
307
|
+
|
308
|
+
if (tRel < 0) {
|
309
|
+
// Grey out when in past
|
310
|
+
if (!livePast[i].classList.contains('text-secondary')) {
|
311
|
+
livePast[i].classList.add('text-secondary');
|
312
|
+
}
|
313
|
+
}
|
314
|
+
else {
|
315
|
+
// Show normal otherwise
|
316
|
+
livePast[i].classList.remove('text-secondary');
|
317
|
+
}
|
318
|
+
}
|
319
|
+
|
320
|
+
// Cancel timer after program is over
|
321
|
+
if (tNow > confEnd && !demo) {
|
322
|
+
stopUpdateLive();
|
323
|
+
}
|
324
|
+
};
|
325
|
+
|
326
|
+
const startUpdateLive = () => {
|
327
|
+
// Start update timer to update live elements in DOM
|
328
|
+
stopUpdateLive();
|
329
|
+
updateLive();
|
330
|
+
|
331
|
+
if (demo) {
|
332
|
+
// Immediate start required since delayStart would wait for next wrap around
|
333
|
+
liveTimer = setInterval(updateLive, timeUnit() * 1000);
|
334
|
+
}
|
335
|
+
else {
|
336
|
+
setTimeout(() => {
|
337
|
+
liveTimer = setInterval(updateLive, timeUnit() * 1000);
|
338
|
+
updateLive();
|
339
|
+
}, delayStart(confStart) * 1000);
|
340
|
+
}
|
341
|
+
};
|
342
|
+
|
343
|
+
const stopUpdateLive = () => {
|
344
|
+
// stopUpdate update timer to update live elements in DOM
|
345
|
+
if (typeof liveTimer !== "undefined") {
|
346
|
+
clearInterval(liveTimer);
|
347
|
+
}
|
348
|
+
};
|
349
|
+
|
350
|
+
let streamModal;
|
351
|
+
|
352
|
+
const getRoom = (roomName) => {
|
353
|
+
// Return room object for given room name
|
354
|
+
if (roomName in data.rooms) {
|
355
|
+
return data.rooms[roomName];
|
356
|
+
}
|
357
|
+
else {
|
358
|
+
return data.rooms[Object.keys(data.rooms)[0]];
|
359
|
+
}
|
360
|
+
};
|
361
|
+
|
362
|
+
const getTalks = (roomName) => {
|
363
|
+
if (roomName in data.talks) {
|
364
|
+
return data.talks[roomName];
|
365
|
+
}
|
366
|
+
else {
|
367
|
+
return false;
|
368
|
+
}
|
369
|
+
};
|
370
|
+
|
371
|
+
const getNextTalk = (roomName) => {
|
372
|
+
// Get talk object for next talk in given room
|
373
|
+
const timeNow = time();
|
374
|
+
const talksHere = getTalks(roomName);
|
375
|
+
|
376
|
+
if (talksHere) {
|
377
|
+
if (timeNow < talksHere[talksHere.length-1].end) {
|
378
|
+
for (let i = 0; i < talksHere.length; i++) {
|
379
|
+
if (timeNow < talksHere[i].end) {
|
380
|
+
return talksHere[i];
|
381
|
+
}
|
382
|
+
}
|
383
|
+
}
|
384
|
+
}
|
385
|
+
return false;
|
386
|
+
};
|
387
|
+
|
388
|
+
const getNextPause = (roomName) => {
|
389
|
+
// Get time object for next pause in given room
|
390
|
+
const timeNow = time();
|
391
|
+
const talksHere = getTalks(roomName);
|
392
|
+
|
393
|
+
if (talksHere) {
|
394
|
+
if (timeNow < talksHere[talksHere.length-1].end) {
|
395
|
+
for (let i = 1; i < talksHere.length; i++) {
|
396
|
+
if (timeNow < talksHere[i].start && streamPause*60 <= talksHere[i].start - talksHere[i-1].end) {
|
397
|
+
return {
|
398
|
+
'start': talksHere[i-1].end,
|
399
|
+
'end': talksHere[i].start,
|
400
|
+
};
|
401
|
+
}
|
402
|
+
}
|
403
|
+
}
|
404
|
+
}
|
405
|
+
return false;
|
406
|
+
};
|
407
|
+
|
408
|
+
const setStreamIframeContent = (content) => {
|
409
|
+
// Set stream modal iframe to show given text
|
410
|
+
streamModal.find('iframe').attr('src', '');
|
411
|
+
streamModal.find('iframe').addClass('d-none');
|
412
|
+
streamModal.find('#stream-placeholder > div').text(content);
|
413
|
+
streamModal.find('#stream-placeholder').addClass('d-flex');
|
414
|
+
};
|
415
|
+
|
416
|
+
const setStreamIframeSrc = (href) => {
|
417
|
+
// Set stream modal iframe to show given URL
|
418
|
+
streamModal.find('iframe').attr('src', href);
|
419
|
+
streamModal.find('#stream-placeholder').addClass('d-none').removeClass('d-flex');
|
420
|
+
streamModal.find('iframe').removeClass('d-none');
|
421
|
+
};
|
422
|
+
|
423
|
+
const setStreamVideo = (roomName) => {
|
424
|
+
// Update stream modal iframe:
|
425
|
+
// Show stream with start/pause/end message (for given room) and keep updated
|
426
|
+
const timeNow = time();
|
427
|
+
|
428
|
+
const talksHere = getTalks(roomName);
|
429
|
+
let roomStart, roomEnd;
|
430
|
+
if (talksHere) {
|
431
|
+
roomStart = talksHere[0].start;
|
432
|
+
roomEnd = talksHere[talksHere.length-1].end;
|
433
|
+
}
|
434
|
+
else {
|
435
|
+
// If no program for given room, take overall first and last talk
|
436
|
+
roomStart = 0;
|
437
|
+
roomEnd = 0;
|
438
|
+
for (let roomNameTalk in data.talks) {
|
439
|
+
talksHere = getTalks(roomNameTalk);
|
440
|
+
const crntRoomStart = talksHere[0].start;
|
441
|
+
const crntRoomEnd = talksHere[talksHere.length-1].end;
|
442
|
+
|
443
|
+
if (roomStart == 0 || roomStart > crntRoomStart) {
|
444
|
+
roomStart = crntRoomStart;
|
445
|
+
}
|
446
|
+
if (roomEnd == 0 || roomEnd < crntRoomEnd) {
|
447
|
+
roomEnd = crntRoomEnd;
|
448
|
+
}
|
449
|
+
}
|
450
|
+
}
|
451
|
+
|
452
|
+
if (typeof streamVideoTimer !== "undefined") {
|
453
|
+
clearInterval(streamVideoTimer);
|
454
|
+
}
|
455
|
+
|
456
|
+
// Conference not yet started
|
457
|
+
if (timeNow < roomStart - streamPrepend*60) {
|
458
|
+
setStreamIframeContent(lang.pre_stream);
|
459
|
+
|
460
|
+
if (!freezeTime) {
|
461
|
+
streamVideoTimer = setTimeout(setStreamVideo, delayStart(roomStart - streamPrepend*60) * 1000, roomName);
|
462
|
+
}
|
463
|
+
}
|
464
|
+
|
465
|
+
// Conference is over
|
466
|
+
else if (timeNow > roomEnd + streamExtend*60) {
|
467
|
+
setStreamIframeContent(lang.post_stream);
|
468
|
+
|
469
|
+
if (!freezeTime && demo) {
|
470
|
+
streamVideoTimer = setTimeout(setStreamVideo, delayStart(roomEnd - streamPrepend*60) * 1000, roomName);
|
471
|
+
}
|
472
|
+
}
|
473
|
+
|
474
|
+
// Conference ongoing
|
475
|
+
else {
|
476
|
+
const pauseNext = getNextPause(roomName);
|
477
|
+
|
478
|
+
// Currently stream is paused
|
479
|
+
if (pauseNext && timeNow >= pauseNext.start + streamExtend*60 && timeNow <= pauseNext.end - streamPrepend*60) {
|
480
|
+
setStreamIframeContent(lang.pause_stream);
|
481
|
+
|
482
|
+
if (!freezeTime) {
|
483
|
+
streamVideoTimer = setTimeout(setStreamVideo, delayStart(pauseNext.end - streamPrepend*60) * 1000, roomName);
|
484
|
+
}
|
485
|
+
}
|
486
|
+
// Currently a talk is active
|
487
|
+
else {
|
488
|
+
const room = getRoom(roomName);
|
489
|
+
setStreamIframeSrc(room.href);
|
490
|
+
|
491
|
+
if (!freezeTime) {
|
492
|
+
if (pauseNext) {
|
493
|
+
streamVideoTimer = setTimeout(setStreamVideo, delayStart(pauseNext.start + streamExtend*60) * 1000, roomName);
|
494
|
+
}
|
495
|
+
else {
|
496
|
+
streamVideoTimer = setTimeout(setStreamVideo, delayStart(roomEnd + streamExtend*60) * 1000, roomName);
|
497
|
+
}
|
498
|
+
}
|
499
|
+
}
|
500
|
+
}
|
501
|
+
};
|
502
|
+
|
503
|
+
const setStreamInfo = (roomName) => {
|
504
|
+
// Update stream modal info bar:
|
505
|
+
// Show next talk and speaker (for given room) and keep updated
|
506
|
+
const timeNow = time();
|
507
|
+
const talkNext = getNextTalk(roomName);
|
508
|
+
|
509
|
+
if (typeof streamInfoTimer !== "undefined") {
|
510
|
+
clearInterval(streamInfoTimer);
|
511
|
+
}
|
512
|
+
|
513
|
+
if (talkNext && timeNow >= talkNext.start - streamPause*60) {
|
514
|
+
document.getElementById('stream-info').dataset.time = talkNext.start;
|
515
|
+
document.getElementById('stream-info-time').dataset.time = talkNext.start;
|
516
|
+
updateLive();
|
517
|
+
|
518
|
+
streamModal.find('#stream-info-color').removeClass((index, className) => {
|
519
|
+
return (className.match(/(^|\s)border-soft-\S+/g) || []).join(' ');
|
520
|
+
});
|
521
|
+
streamModal.find('#stream-info-color').addClass('border-soft-' + talkNext.color);
|
522
|
+
|
523
|
+
streamModal.find('#stream-info-talk').text(talkNext.name).attr('href', talkNext.href);
|
524
|
+
|
525
|
+
let speakerStr = '';
|
526
|
+
for (let i = 0; i < talkNext.speakers.length; i++) {
|
527
|
+
let speaker = data.speakers[talkNext.speakers[i]];
|
528
|
+
if (speaker.href == '') {
|
529
|
+
speakerStr += speaker.name +', '
|
530
|
+
}
|
531
|
+
else {
|
532
|
+
speakerStr += '<a class="text-reset" href="'+ speaker.href +'">'+ speaker.name +'</a>, ';
|
533
|
+
}
|
534
|
+
}
|
535
|
+
speakerStr = speakerStr.slice(0, -2);
|
536
|
+
streamModal.find('#stream-info-speakers').html(speakerStr);
|
537
|
+
|
538
|
+
if (talkNext.live_links) {
|
539
|
+
let linksStr = '';
|
540
|
+
for (let i = 0; i < talkNext.live_links.length; i++) {
|
541
|
+
const link = talkNext.live_links[i];
|
542
|
+
|
543
|
+
linksStr += '<a href="' + link.href + '" class="btn btn-light m-1'
|
544
|
+
if (link.disabled) {
|
545
|
+
linksStr += ' disabled';
|
546
|
+
}
|
547
|
+
linksStr += '">';
|
548
|
+
if (link.icon) {
|
549
|
+
linksStr += '<i class="fas fa-' + link.icon + '"></i> ';
|
550
|
+
}
|
551
|
+
linksStr += link.name + '</a>';
|
552
|
+
}
|
553
|
+
streamModal.find('#stream-info-links').html(linksStr).removeClass('d-none');
|
554
|
+
}
|
555
|
+
else {
|
556
|
+
streamModal.find('#stream-info-links').addClass('d-none');
|
557
|
+
}
|
558
|
+
|
559
|
+
streamModal.find('#stream-info').removeClass('d-none');
|
560
|
+
|
561
|
+
if (!freezeTime) {
|
562
|
+
streamInfoTimer = setTimeout(setStreamInfo, delayStart(talkNext.end) * 1000, roomName);
|
563
|
+
}
|
564
|
+
}
|
565
|
+
else {
|
566
|
+
streamModal.find('#stream-info').addClass('d-none');
|
567
|
+
|
568
|
+
if (!freezeTime) {
|
569
|
+
if (talkNext) {
|
570
|
+
streamInfoTimer = setTimeout(setStreamInfo, delayStart(talkNext.start - streamPause*60) * 1000, roomName);
|
571
|
+
}
|
572
|
+
else if (demo) {
|
573
|
+
let talksHere = getTalks(roomName);
|
574
|
+
if (talksHere) {
|
575
|
+
streamInfoTimer = setTimeout(setStreamInfo, delayStart(talksHere[0].start - streamPrepend*60) * 1000, roomName);
|
576
|
+
}
|
577
|
+
}
|
578
|
+
}
|
579
|
+
}
|
580
|
+
};
|
581
|
+
|
582
|
+
const setStream = (roomName) => {
|
583
|
+
// Update stream modal (iframe and info bar) for given room
|
584
|
+
streamModal.find('.modal-footer .btn').removeClass('active');
|
585
|
+
streamModal.find('#stream-select').val(0);
|
586
|
+
|
587
|
+
// Recover room name in case of empty default
|
588
|
+
const room = getRoom(roomName);
|
589
|
+
roomName = room.name;
|
590
|
+
|
591
|
+
setStreamVideo(roomName);
|
592
|
+
setStreamInfo(roomName);
|
593
|
+
|
594
|
+
streamModal.find('#stream-button' + room.id).addClass('active');
|
595
|
+
streamModal.find('#stream-select').val(room.id);
|
596
|
+
};
|
597
|
+
|
598
|
+
const updateStream = () => {
|
599
|
+
// Update stream modal for currently active room button
|
600
|
+
if (streamModal.hasClass('show')) {
|
601
|
+
let activeButton = streamModal.find('.modal-footer .btn.active');
|
602
|
+
let roomName = activeButton.data('room');
|
603
|
+
|
604
|
+
if (typeof roomName !== "undefined") {
|
605
|
+
setStream(roomName);
|
606
|
+
}
|
607
|
+
}
|
608
|
+
};
|
609
|
+
|
610
|
+
const stopUpdateStream = () => {
|
611
|
+
// Stop stream modal update timer
|
612
|
+
if (typeof streamVideoTimer !== "undefined") {
|
613
|
+
clearInterval(streamVideoTimer);
|
614
|
+
}
|
615
|
+
if (typeof streamInfoTimer !== "undefined") {
|
616
|
+
clearInterval(streamInfoTimer);
|
617
|
+
}
|
618
|
+
};
|
619
|
+
|
620
|
+
const hideModal = () => {
|
621
|
+
// Close stream modal
|
622
|
+
streamModal.find('iframe').attr('src', '');
|
623
|
+
streamModal.find('.modal-footer .btn').removeClass('active');
|
624
|
+
streamModal.find('#stream-select').selectedIndex = -1;
|
625
|
+
};
|
626
|
+
|
627
|
+
const setupStream = () => {
|
628
|
+
// Setup events when modal opens/closes
|
629
|
+
streamModal = $('#stream-modal');
|
630
|
+
|
631
|
+
// configure modal opening buttons
|
632
|
+
streamModal.on('show.bs.modal', (event) => {
|
633
|
+
let button = $(event.relatedTarget);
|
634
|
+
let roomName = button.data('room');
|
635
|
+
setStream(roomName);
|
636
|
+
});
|
637
|
+
streamModal.on('hide.bs.modal', () => {
|
638
|
+
hideModal();
|
639
|
+
});
|
640
|
+
|
641
|
+
// configure room selection buttons in modal
|
642
|
+
streamModal.find('.modal-footer .btn').on('click', function (event) {
|
643
|
+
event.preventDefault();
|
644
|
+
|
645
|
+
let roomName = $(this).data('room');
|
646
|
+
setStream(roomName);
|
647
|
+
});
|
648
|
+
|
649
|
+
// configure room selection menu in modal
|
650
|
+
streamModal.find('#stream-select').on('change', function (event) {
|
651
|
+
event.preventDefault();
|
652
|
+
|
653
|
+
let roomName = $(this).children('option:selected').text();
|
654
|
+
setStream(roomName);
|
655
|
+
});
|
656
|
+
};
|
657
|
+
|
658
|
+
const init = (c, l) => {
|
659
|
+
config = c;
|
660
|
+
lang = l;
|
661
|
+
|
662
|
+
confStart = config.time.start;
|
663
|
+
confEnd = config.time.end;
|
664
|
+
confDur = confEnd - confStart;
|
665
|
+
|
666
|
+
demo = config.demo.enable;
|
667
|
+
demoDur = config.demo.duration;
|
668
|
+
demoPause = config.demo.pause;
|
669
|
+
demoStart = confStart - confDur/demoDur*demoPause;
|
670
|
+
demoEnd = confEnd + confDur/demoDur*demoPause;
|
671
|
+
|
672
|
+
stream = config.streaming.enable;
|
673
|
+
streamPause = config.streaming.pause;
|
674
|
+
streamPrepend = config.streaming.prepend;
|
675
|
+
streamExtend = config.streaming.extend;
|
676
|
+
|
677
|
+
loadData();
|
678
|
+
startUpdateLive();
|
679
|
+
if (stream) {
|
680
|
+
setupStream();
|
681
|
+
}
|
682
|
+
};
|
683
|
+
|
684
|
+
const update = () => {
|
685
|
+
updateLive();
|
686
|
+
if (stream) {
|
687
|
+
updateStream();
|
688
|
+
}
|
689
|
+
};
|
690
|
+
|
691
|
+
const startUpdate = () => {
|
692
|
+
startUpdateLive();
|
693
|
+
if (stream) {
|
694
|
+
updateStream();
|
695
|
+
}
|
696
|
+
};
|
697
|
+
|
698
|
+
const stopUpdate = () => {
|
699
|
+
stopUpdateLive();
|
700
|
+
if (stream) {
|
701
|
+
stopUpdateStream();
|
702
|
+
}
|
703
|
+
};
|
704
|
+
|
705
|
+
return {
|
706
|
+
init: init,
|
707
|
+
getData: getData,
|
708
|
+
|
709
|
+
pauseTime: pauseTime,
|
710
|
+
continueTime: continueTime,
|
711
|
+
resetTime: resetTime,
|
712
|
+
setTime: setTime,
|
713
|
+
getTime: getTime,
|
714
|
+
|
715
|
+
demo: model.demo
|
716
|
+
};
|
717
|
+
|
718
|
+
})();
|