devops4lib-jekyll-theme-conference 0.0.1

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