jekyll-theme-conference 2.3.0 → 2.5.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9a0fad6956153d771e9df4ec3913930b83fd63578f2dfe4fa7f75cd3ae86c646
4
- data.tar.gz: 26095d7b5815eb8d5a40e1a930cce74eeaf608d5f3b1dfa7eaad3882bcdba078
3
+ metadata.gz: 7a6617ea192ab16d014da7430f23276860d7ecce37cdd591815103bb086efb65
4
+ data.tar.gz: a31e631388e20578008dcef761e416a5a53c53166b068ecb410ee0f75b1f9196
5
5
  SHA512:
6
- metadata.gz: a5478b0f9e44fcbf373a26e60edf545c102757f3bc2dc50ad2b8edbb7a557826135a87dc4b692d2e8caecac970a82112abf9dc887aff6557fbd7e66756b6001e
7
- data.tar.gz: ae1b7d2aef7316b2a17b4df34b69e59dd11b7c66201c89c618f7b4ee5591c1887b19cd6eee72808c612934963ecac55960cbdeb4330706095c6bdfd231fee569
6
+ metadata.gz: ef931eb98d10bc467358f2948e76b15ac8d11a8abe1d7528688a5f672fcb8127a31cbe46165f41b355d58d186ca83a5d010d5b5cb0abfb41f685296c908421ae
7
+ data.tar.gz: a3ef7ee1df36b5280534f5819d10c21c2447f9430650e89d0aa4923243656d51d4e2483c888adfe2e30cfb18b0e0d40584add7dc4c3449ba997d604d1f6b9684
data/README.md CHANGED
@@ -89,6 +89,10 @@ The different talks, speakers and rooms are stored as a collection of files. Eac
89
89
 
90
90
  The actual schedule defining when and in which room a talk takes place is stored as a [YAML data file](https://jekyllrb.com/docs/datafiles/) under `_data/program.yml`. For further details about it see below in the section _Content_.
91
91
 
92
+ :warning: Please note that the generated website can be quite large containing many unnecessary whitespaces. It is recommended to minimize the generated output files before uploading them to a server (e.g. with [minify](https://github.com/tdewolff/minify)).
93
+
94
+ ### Jump Start
95
+
92
96
  In order to be up and running simply use the default content of this repository as an initial base for your new website. After having setup a new Jekyll website copy the following files and folders into the website's folder:
93
97
 
94
98
  - `_config.example.yml` -> `_config.yml`
@@ -102,11 +106,23 @@ In order to be up and running simply use the default content of this repository
102
106
  - `speakers/`
103
107
  - `talks/`
104
108
 
105
- There exists a Python file in this repository, `create_entries.py`, which can be used to import content from a CSV table and generate the different talk, speakers and room files automatically based on it. Just open your terminal and type `python create_entries.py --help` to show the help and get started.
109
+ ### Automatic Import
110
+
111
+ There exists a Python file in this repository, `create_entries.py`, which can be used to import content from a [frab](https://github.com/frab/frab/wiki/Manual#introduction) compatible JSON file or a CSV table and generate the different talk, speakers and room files automatically based on it. Just open your terminal and type `python create_entries.py --help` to show the help and get started.
106
112
 
107
- In case you do not want to install the entire Ruby/Jekyll toolchain on your machine you can make use of [GitHub Actions](https://github.com/features/actions), Github's continuous integration platform. This repository contains an example Github Action configuration file which automatically builds the website upon adding a new tag. It then attaches the generated website as package to a release for easy downloading. Simply copy the following file to your repository and adapt it to your needs:
113
+ ### Automatic Build
108
114
 
109
- - `workflows.example.yml` -> `.github/workflows.main.yml`
115
+ In case you do not want to install the entire Ruby/Jekyll toolchain on your machine you can make use of [GitHub Actions](https://github.com/features/actions), Github's continuous integration platform. This repository contains an example Github Action configuration file which automatically builds and minimizes the website upon adding a new tag. It then attaches the generated website as package to a release for easy downloading. Simply copy the following file to your repository and adapt it to your needs:
116
+
117
+ - `workflow-example.yml` -> `.github/workflows/main.yml`
118
+
119
+ Hidden rooms, speakers, or talks are automatically generated in way containing no content. In order to remove these empty files simply add a file called `delete_hidden.sh` to the root with the following content. It will automatically called by the Github Action workflow to delete the files.
120
+
121
+ ```markdown
122
+ ---
123
+ layout: delete_hidden
124
+ ---
125
+ ```
110
126
 
111
127
 
112
128
  ## Configuration
@@ -124,6 +140,8 @@ conference:
124
140
  show_errors: false
125
141
  ```
126
142
 
143
+ :warning: Please be sure to disable this parameter for your production system.
144
+
127
145
  ### Collection URLs
128
146
 
129
147
  The three required collections containing the files for the talks, speakers and rooms have to be specified in the `_config.yml` file. The first block declares them and sets the URL under which they will later be accessed. The second block defines the default layout for each of the collection.
@@ -165,7 +183,7 @@ _Note:_ While you might want to change the URLs, the name of the three collectio
165
183
 
166
184
  ### Language
167
185
 
168
- In order to adapt the language of the theme set the `lang` property. Make sure you have copied the internationalization file from this repository to `_data/lang.yml`. Currently the following languages are supported:
186
+ In order to adapt the language of the theme set the `lang` property. If you change it from its default, make sure you have copied the internationalization file from this repository to `_data/lang.yml`. Currently the following languages are included:
169
187
 
170
188
  - English: `en` (Default)
171
189
  - German: `de`
@@ -185,7 +203,8 @@ The navigation bar is located at the top and visible on every site. On the right
185
203
 
186
204
  Additionally, a navigation bar link can also have the following properties:
187
205
 
188
- - `menu` containing another list of links. This creates a dropdown menu of multiple sublinks. The sublinks have the same properties as regular links (see the _Content_ > _Links_ section).
206
+ - `menu` containing another list of links. This creates a dropdown menu of multiple sublinks. The sublinks have the same properties as regular links (see the _Content_ > _Links_ section), or
207
+ - `live` making the link only visible during the conference and adds a live indication. The `name` property can be omitted. If streaming is enabled and any URL property is omitted, a click on the link will open the streaming modal (see section _Live Indications_ below).
189
208
 
190
209
  Example:
191
210
 
@@ -195,6 +214,7 @@ conference:
195
214
  links:
196
215
  - name: Program
197
216
  relative_url: /program/
217
+ - live: true
198
218
  - name: Previous Editions
199
219
  menu:
200
220
  - name: 2020 (current)
@@ -224,7 +244,7 @@ conference:
224
244
 
225
245
  The main landing page is shown at the root of the website to greet new visitors. In order to show it you need to create a `index.md` file in the root of your website's folder and specify its layout as `layout: main`. The remaining customizations are specified in the `_config.yml` file.
226
246
 
227
- The main page states your site's title (`site.title`) or a logo instead. The logo can be configured through the `logo` property under the `main` property containing:
247
+ The main page states your site's title (`site.title`) or a logo instead. The logo can be configured through the `logo` property under the `main` property containing
228
248
 
229
249
  - a `img` property specifying the path to the image file relative to the `/assets/images/` folder.
230
250
 
@@ -286,7 +306,31 @@ conference:
286
306
  Try again next year.
287
307
  ```
288
308
 
289
- ### Talk Settings: Main Categories and Icons
309
+ ### Live Indications & Streaming
310
+
311
+ In order to help users navigating the program during the congress, a _Live_ indication can be shown next to talks which are currently taking place. A small JavaScript functions keeps the site automatically up-to-date (without the need to refresh) showing the indication as soon as the talk has started and hiding it once it is over (according to the timetable indicated in the `_data/program.yml` file).
312
+
313
+ This can be further extended if some of the talks have an associated live stream: Upon clicking one of the live indications a modal will open containing the corresponding live stream embedded. The URL to the live stream has to be set via `live` property in each room (see the _Content_ > _Room_ section below).
314
+
315
+ In order to activate the functionality the `live` property has to be set containing
316
+
317
+ - the date of the day at which the conference takes place (`date`),
318
+ - the timezone in which the conference takes place (`timezone`),
319
+ - optionally if streaming is enabled (`streaming`) with indications how many minutes early the stream will begin and end, and
320
+ - optionally a demo mode setting, whereby the JavaScript function cycles through the entire program in five minutes for demonstration purposes (`demo: true`, default: `false`).
321
+
322
+ ```yaml
323
+ conference:
324
+ live:
325
+ date: 01.01.2020
326
+ timezone: GMT+1
327
+ streaming:
328
+ start_early: 15 # in minutes
329
+ end_late: 0 # in minutes
330
+ demo: false
331
+ ```
332
+
333
+ ### Talk Settings
290
334
 
291
335
  Each talk can have one or multiple categories associated via FrontMatter (see the _Individual Pages: Talks_ section below for more details). Some of these categories can be elevated to so called main categories". These are used to color group the talks across the entire website, particularly in the program. In order to do so add the `main_categories` property under the `talks` property. It consists of a list of all main categories. Each main category consists of:
292
336
 
@@ -314,11 +358,12 @@ conference:
314
358
  color: info
315
359
  - name: Cat B
316
360
  color: success
361
+
317
362
  # Hide icons on talk overview page
318
363
  hide_icons: false
319
364
  ```
320
365
 
321
- ### Speaker Settings: First name
366
+ ### Speaker Settings
322
367
 
323
368
  In the program as well as the speaker's overview the speaker's first name can be abbreviated to its first letter. Of course, you also have the option to not specify a first name for each speaker in the first place. In order to shorten the first name add the `show_firstname: true` setting (default: `false`) to the `speakers` property.
324
369
 
@@ -330,7 +375,7 @@ conference:
330
375
  show_firstname: false
331
376
  ```
332
377
 
333
- ### Location Settings: Hide all and configure map
378
+ ### Location Settings
334
379
 
335
380
  In case the location of your rooms is obvious (e.g. on a campus) you can decide to disable the location page and links to all the rooms. You still need to create the different rooms as files in the `_rooms/` directory, since they are needed as a reference. But there will not be any link pointing to it (effectively hiding them).
336
381
  In order to hide all rooms add the `hide: true` setting (default: `false`) to the `location` property.
@@ -353,7 +398,7 @@ conference:
353
398
  map_provider: "OpenStreetMap.Mapnik"
354
399
  ```
355
400
 
356
- The map is based on the JavaScript Library [Leaflet](https://leafletjs.com/) and can be customized by editing the `assets/js/main.js` file, e.g. adding additional layers with markers, text, or shapes to the map. To start, copy simply the file from this repository and make use of the initialized global variable `map` pointing to the Leaflet container.
401
+ The map is based on the JavaScript Library [Leaflet](https://leafletjs.com/) and can be customized by editing the `assets/js/main.js` file, e.g. adding additional layers with markers, text, or shapes to the map. To start, copy simply the file from this repository and make use of the initialized global variable `window.conference.map` pointing to the Leaflet container.
357
402
 
358
403
  Example:
359
404
 
@@ -364,11 +409,13 @@ Example:
364
409
  {% include js/conference.js %}
365
410
 
366
411
  (function() {
412
+ let map = window.conference.map;
413
+
367
414
  if (typeof map !== 'undefined') {
368
415
  var main_station = L.marker([47.37785, 8.54035], {
369
416
  icon: L.divIcon({
370
417
  className: '',
371
- html: '<span class="fas fa-train"></span> Bahnhof Zürich',
418
+ html: '<span class="fas fa-train"></span> Main Station',
372
419
  iconSize: [120, 56]
373
420
  })
374
421
  }).addTo(map);
@@ -454,8 +501,9 @@ Each speaker is represented by a file in the `_speakers/` directory. It must beg
454
501
 
455
502
  Each room is represented by a file in the `_rooms/` directory. It must begin with valid [YAML Front Matter](https://jekyllrb.com/docs/frontmatter/) containing
456
503
 
457
- - the room's `name`, and
458
- - optionally `hide: true` if the room's page should not be linked to.
504
+ - the room's `name`
505
+ - optionally `hide: true` if the room's page should not be linked to, and
506
+ - optionally a URL pointing to a live stream for the given room during the conference (`live`, see the section _Live Indications & Streaming_ above).
459
507
 
460
508
  ### Links
461
509
 
@@ -0,0 +1,415 @@
1
+ window.conference.live = (function() {
2
+ {%- include partials/get_conf_time.html -%}
3
+ {%- assign time_start = conf_start -%}
4
+ {%- assign time_end = conf_end -%}
5
+ {%- include partials/get_timestamp.html -%}
6
+
7
+ let confStart = {{ timestamp_start }};
8
+ let confEnd = {{ timestamp_end }};
9
+ let confDur = confEnd - confStart;
10
+
11
+ let freezeTime = false;
12
+ let timeFrozen = 0;
13
+ let timeOffset = 0;
14
+
15
+ let demo = {{ site.conference.live.demo | default: "false" }};
16
+ let durDemo = 5*60; // in seconds
17
+ let durPause = 10; // in seconds
18
+
19
+ let demoStart = confStart - confDur/durDemo*durPause;
20
+ let demoEnd = confEnd + confDur/durDemo*durPause;
21
+
22
+ let liveTimer;
23
+ let streamTimer;
24
+
25
+ let mod = function (n, m) {
26
+ return ((n % m) + m) % m;
27
+ };
28
+
29
+ let timeNow = function () {
30
+ return Math.floor(Date.now() / 1000);
31
+ };
32
+
33
+ let timeCont = function () {
34
+ return timeNow() - timeOffset;
35
+ };
36
+
37
+ let timeCycle = function () {
38
+ let actTime = timeNow();
39
+ let relTime = mod(actTime, durDemo + 2*durPause) / durDemo;
40
+ let cycleTime = mod((demoEnd - demoStart) * relTime - timeOffset, (demoEnd - demoStart)) + demoStart;
41
+ return cycleTime;
42
+ };
43
+
44
+ let time = function () {
45
+ if (freezeTime) {
46
+ return timeFrozen;
47
+ }
48
+ else if (demo) {
49
+ return timeCycle();
50
+ }
51
+ else {
52
+ return timeCont();
53
+ }
54
+ };
55
+
56
+ let pauseTime = function () {
57
+ if (!freezeTime) {
58
+ timeFrozen = time();
59
+ freezeTime = true;
60
+
61
+ stopUpdate();
62
+ }
63
+ };
64
+
65
+ let continueTime = function () {
66
+ if (freezeTime) {
67
+ freezeTime = false;
68
+ timeOffset += time() - timeFrozen;
69
+ startUpdate();
70
+ }
71
+ };
72
+
73
+ let resetTime = function (timeStr) {
74
+ timeOffset = 0;
75
+ freezeTime = false;
76
+
77
+ startUpdate();
78
+ };
79
+
80
+ let setTime = function (newTime) {
81
+ pauseTime();
82
+
83
+ let d = new Date(confStart * 1000);
84
+ newTime = newTime.split(':');
85
+ d.setHours(newTime[0], newTime[1]);
86
+
87
+ timeFrozen = Math.floor(d.getTime() / 1000);
88
+
89
+ update();
90
+ };
91
+
92
+ let getTime = function (tConvert = time()) {
93
+ let d = new Date(tConvert * 1000);
94
+ let h = d.getHours();
95
+ let m = d.getMinutes();
96
+
97
+ return h + ":" + (m < 10 ? "0" : "") + m;
98
+ };
99
+
100
+ let timeUnit = function () {
101
+ if (demo) {
102
+ return 0.1;
103
+ }
104
+ else {
105
+ return 60;
106
+ }
107
+ };
108
+
109
+ let delayStart = function (startTime) {
110
+ let tNow = time();
111
+ let tUnit = timeUnit();
112
+
113
+ if (demo) {
114
+ // Convert virtual duration to real duration
115
+ return mod(startTime - tNow, demoEnd - demoStart) / (demoEnd - demoStart) * (durDemo + 2*durPause);
116
+ }
117
+ else {
118
+ if (startTime > tNow) {
119
+ return startTime - tNow;
120
+ }
121
+ else {
122
+ // Start on the unit
123
+ return (tUnit - (tNow % tUnit));
124
+ }
125
+ }
126
+ };
127
+
128
+ let toggleDemo = function () {
129
+ demo = !demo;
130
+ resetTime();
131
+ };
132
+
133
+ let demoOn = function () {
134
+ return demo;
135
+ };
136
+
137
+ let updateLive = function () {
138
+ let tNow = time();
139
+ let liveShow = document.getElementsByClassName('live-show');
140
+ let liveHide = document.getElementsByClassName('live-hide');
141
+
142
+ for (let i = 0; i < liveShow.length; i++) {
143
+ let tStart = liveShow[i].dataset.start;
144
+ let tEnd = liveShow[i].dataset.end;
145
+
146
+ if (tNow >= tStart && tNow < tEnd) {
147
+ // Show when active
148
+ liveShow[i].classList.remove('d-none');
149
+ }
150
+ else if (!liveShow[i].classList.contains('d-none')) {
151
+ // Hide otherwise
152
+ liveShow[i].classList.add('d-none');
153
+ }
154
+ }
155
+
156
+ for (let i = 0; i < liveHide.length; i++) {
157
+ let tStart = liveHide[i].dataset.start;
158
+ let tEnd = liveHide[i].dataset.end;
159
+
160
+ if (tNow >= tStart && tNow < tEnd) {
161
+ // Hide when active
162
+ if (!liveHide[i].classList.contains('d-none')) {
163
+ liveHide[i].classList.add('d-none');
164
+ }
165
+ }
166
+ else {
167
+ // Show otherwise
168
+ liveHide[i].classList.remove('d-none');
169
+ }
170
+ }
171
+
172
+ if (tNow > confEnd && !demo) {
173
+ // Cancel timer after program is over
174
+ stopUpdateLive();
175
+ }
176
+ };
177
+
178
+ let startUpdateLive = function () {
179
+ stopUpdateLive();
180
+ updateLive();
181
+
182
+ if (demo) {
183
+ // Immediate start required since delayStart would wait for next wrap around
184
+ liveTimer = setInterval(updateLive, timeUnit() * 1000);
185
+ }
186
+ else {
187
+ setTimeout(function() {
188
+ liveTimer = setInterval(updateLive, timeUnit() * 1000);
189
+ updateLive();
190
+ }, delayStart(confStart) * 1000);
191
+ }
192
+ };
193
+
194
+ let stopUpdateLive = function () {
195
+ if (typeof liveTimer !== "undefined") {
196
+ clearInterval(liveTimer);
197
+ }
198
+ };
199
+
200
+ {% if site.conference.live.streaming -%}
201
+
202
+ let rooms = {
203
+ {%- for r in site.data.program -%}
204
+ {%- assign room = site.rooms | where: 'name', r.room | first -%}
205
+ {%- if room.live -%}
206
+
207
+ {%- assign t = r.talks | first -%}
208
+ {%- include partials/get_talk_time.html -%}
209
+ {%- assign time_start = talk_start -%}
210
+ {%- assign time_end = talk_end -%}
211
+ {%- include partials/get_timestamp.html -%}
212
+
213
+ {%- assign offset_start = site.conference.live.streaming.start_early | default: 0 -%}
214
+ {%- assign room_ts_start = offset_start | times: -60 | plus: timestamp_start -%}
215
+
216
+ {%- assign t = r.talks | last -%}
217
+ {%- include partials/get_talk_time.html -%}
218
+ {%- assign time_start = talk_start -%}
219
+ {%- assign time_end = talk_end -%}
220
+ {%- include partials/get_timestamp.html -%}
221
+
222
+ {%- assign offset_end = site.conference.live.streaming.end_late | default: 0 -%}
223
+ {%- assign room_ts_end = offset_end | times: 60 | plus: timestamp_end -%}
224
+
225
+ "{{ room.name }}": {
226
+ "id": {{ forloop.index }},
227
+ "href": "{{ room.live }}",
228
+ "start": {{ room_ts_start }},
229
+ "end": {{ room_ts_end }}
230
+ },
231
+ {%- endif -%}
232
+ {%- endfor -%}
233
+ };
234
+
235
+ let streamModal;
236
+
237
+ let getRoom = function (roomName) {
238
+ if (roomName in rooms) {
239
+ return rooms[roomName];
240
+ }
241
+ else {
242
+ return rooms[Object.keys(rooms)[0]];
243
+ }
244
+ };
245
+
246
+ let preStartStream = function (roomName) {
247
+ let room = getRoom(roomName);
248
+
249
+ streamModal.find('iframe').attr('src', '');
250
+ streamModal.find('iframe').addClass('d-none');
251
+ streamModal.find('#stream-placeholder > div').text('{{ site.data.lang[site.conference.lang].live.pre_stream | default: "Live stream has not started yet." }}');
252
+ streamModal.find('#stream-placeholder').addClass('d-flex');
253
+
254
+ stopUpdateStream();
255
+ if (!freezeTime) {
256
+ streamTimer = setTimeout(activeStream, delayStart(room.start) * 1000, roomName);
257
+ }
258
+ };
259
+
260
+ let activeStream = function (roomName) {
261
+ let room = getRoom(roomName);
262
+
263
+ streamModal.find('iframe').attr('src', room.href);
264
+ streamModal.find('#stream-placeholder').addClass('d-none').removeClass('d-flex');
265
+ streamModal.find('iframe').removeClass('d-none');
266
+
267
+ stopUpdateStream();
268
+ if (!freezeTime) {
269
+ streamTimer = setTimeout(postEndStream, delayStart(room.end) * 1000, roomName);
270
+ }
271
+ };
272
+
273
+ let postEndStream = function (roomName) {
274
+ let room = getRoom(roomName);
275
+
276
+ streamModal.find('iframe').attr('src', '');
277
+ streamModal.find('iframe').addClass('d-none');
278
+ streamModal.find('#stream-placeholder > div').text('{{ site.data.lang[site.conference.lang].live.post_stream | default: "Live stream has ended." }}');
279
+ streamModal.find('#stream-placeholder').addClass('d-flex');
280
+
281
+ stopUpdateStream();
282
+ if (!freezeTime && demo) {
283
+ streamTimer = setTimeout(preStartStream, delayStart(demoStart) * 1000, roomName);
284
+ }
285
+ };
286
+
287
+ let setStream = function (roomName) {
288
+ streamModal.find('.modal-footer .btn').removeClass('active');
289
+ streamModal.find('#stream-select').selectedIndex = -1;
290
+
291
+ let room = getRoom(roomName);
292
+ let tNow = time();
293
+
294
+ if (tNow < room.start) {
295
+ preStartStream(roomName);
296
+ }
297
+ else if (tNow > room.end) {
298
+ postEndStream(roomName);
299
+ }
300
+ else {
301
+ activeStream(roomName);
302
+ }
303
+
304
+ streamModal.find('#stream-button' + room.id).addClass('active');
305
+ streamModal.find('#stream-select').selectedIndex = room.id;
306
+ };
307
+
308
+ let updateStream = function () {
309
+ if (streamModal.hasClass('show')) {
310
+ let activeButton = streamModal.find('.modal-footer .btn.active');
311
+ let roomName = activeButton.data('room');
312
+
313
+ if (typeof roomName !== "undefined") {
314
+ setStream(roomName);
315
+ }
316
+ }
317
+ };
318
+
319
+ let stopUpdateStream = function () {
320
+ if (typeof streamTimer !== "undefined") {
321
+ clearInterval(streamTimer);
322
+ }
323
+ };
324
+
325
+ let hideModal = function (event) {
326
+ streamModal.find('iframe').attr('src', '');
327
+ streamModal.find('.modal-footer .btn').removeClass('active');
328
+ streamModal.find('#stream-select').selectedIndex = -1;
329
+ };
330
+
331
+ let setupStream = function () {
332
+ streamModal = $('#stream-modal');
333
+
334
+ streamModal.on('show.bs.modal', function (event) {
335
+ let button = $(event.relatedTarget);
336
+ let roomName = button.data('room');
337
+ setStream(roomName);
338
+ });
339
+ streamModal.on('hide.bs.modal', function (event) {
340
+ hideModal(event);
341
+ });
342
+
343
+ streamModal.find('.modal-footer .btn').on('click', function(event) {
344
+ event.preventDefault();
345
+
346
+ let roomName = $(this).data('room');
347
+ setStream(roomName);
348
+ });
349
+
350
+ streamModal.find('#stream-select').on('change', function(event) {
351
+ event.preventDefault();
352
+
353
+ let roomName = $(this).children('option:selected').text();
354
+ setStream(roomName);
355
+ });
356
+ };
357
+
358
+ let setup = function () {
359
+ startUpdateLive();
360
+ setupStream();
361
+ };
362
+
363
+ let update = function () {
364
+ updateLive();
365
+ updateStream();
366
+ };
367
+
368
+ let startUpdate = function () {
369
+ startUpdateLive();
370
+ updateStream();
371
+ };
372
+
373
+ let stopUpdate = function () {
374
+ stopUpdateLive();
375
+ stopUpdateStream();
376
+ };
377
+
378
+ {%- else -%}
379
+
380
+ let setup = function () {
381
+ startUpdateLive();
382
+ };
383
+
384
+ let update = function () {
385
+ updateLive();
386
+ };
387
+
388
+ let startUpdate = function () {
389
+ startUpdateLive();
390
+ };
391
+
392
+ let stopUpdate = function () {
393
+ stopUpdateLive();
394
+ };
395
+
396
+ {%- endif %}
397
+
398
+ return {
399
+ init: setup,
400
+
401
+ pauseTime: pauseTime,
402
+ continueTime: continueTime,
403
+ resetTime: resetTime,
404
+ setTime: setTime,
405
+ getTime: getTime,
406
+
407
+ toggleDemo: toggleDemo,
408
+ demo: demoOn,
409
+ durDemo: durDemo,
410
+ durPause: durPause
411
+ };
412
+
413
+ })();
414
+
415
+ window.conference.live.init();