jekyll-theme-conference 3.4.1 → 3.5.0

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