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.
@@ -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();