diff --git a/README.md b/README.md index e3477a82..6d2b1ae7 100644 --- a/README.md +++ b/README.md @@ -503,11 +503,11 @@ Example: {% include js/conference.js %} -(function() { - let map = window.conference.map; +(() => { + const map = window.conference.map; if (typeof map !== 'undefined') { - var main_station = L.marker([47.37785, 8.54035], { + let main_station = L.marker([47.37785, 8.54035], { icon: L.divIcon({ className: '', html: ' Main Station', diff --git a/_includes/js/conference.js b/_includes/js/conference.js index a037d54a..7e963d9b 100644 --- a/_includes/js/conference.js +++ b/_includes/js/conference.js @@ -1,13 +1,19 @@ -// Global app variable -window.conference = {}; - -// Bootstrap (Style Framework) +// Libraries +// Bootstrap (Style Framework) {% include js/lib/jquery-3.5.1.min.js %} {% include js/lib/popper.min.js %} {% include js/lib/bootstrap.js %} -// FontAwesome (Icons) -// Imported via CSS and webfonts +// FontAwesome (Icons) +// Imported via CSS and webfonts + +// Conference +window.conference = { + config: { + baseurl: '{{ site.baseurl }}' + } +}; + // Program {% include js/lib/syncscroll.js %} @@ -31,3 +37,6 @@ window.conference = {}; {% if site.conference.live %} {% include js/live.js %} {% endif %} + +// Load configuration and start initialization +{% include js/init.js %} diff --git a/_includes/js/init.js b/_includes/js/init.js new file mode 100644 index 00000000..abcd6c2c --- /dev/null +++ b/_includes/js/init.js @@ -0,0 +1,37 @@ +const init = () => { + // Load configuration + const request = new Request(window.conference.config.baseurl + '/assets/js/config.json'); + + fetch(request) + .then(response => + response.json() + ) + .then(config => { + // Add configuration to global scope + window.conference.config = Object.assign(window.conference.config, config); + + // Execute initialization functions + for (const [name, module] of Object.entries(window.conference)) { + if (name == 'config') { + continue; + } + + let c; + if (name in config) { + c = config[name]; + } + let l; + if (name in config.lang) { + l = config.lang[name]; + } + + module.init(c, l) + } + + }) + .catch((error) => { + console.log(error); + }); +}; + +init(); diff --git a/_includes/js/live.js b/_includes/js/live.js index 87a98124..c52bad4f 100644 --- a/_includes/js/live.js +++ b/_includes/js/live.js @@ -1,74 +1,77 @@ -window.conference.live = (function() { - {% assign d = site.data.program.days | first -%} - {%- include partials/get_day_time.html -%} - {%- assign t = day_start_talk -%} +window.conference.live = (() => { + let config; + let lang; - {%- include partials/get_talk_timestamp.html -%} - {%- assign conf_start = timestamp_start -%} - - {%- assign d = site.data.program.days | last -%} - {%- include partials/get_day_time.html -%} - {%- assign t = day_end_talk -%} + let data; - {%- include partials/get_talk_timestamp.html -%} - {%- assign conf_end = timestamp_end -%} + let confStart; + let confEnd; + let confDur; - let data; + let stream; + let streamPause; + let streamPrepend; + let streamExtend; - const confStart = {{ conf_start }}; - const confEnd = {{ conf_end }}; - const confDur = confEnd - confStart; + let demo; + let demoStart; + let demoEnd; + let demoDur; + let demoPause; let freezeTime = false; let timeFrozen = 0; let timeOffset = 0; - let demo = {{ site.conference.live.demo.enable | default: "false" }}; - let demoDur = {{ site.conference.live.demo.duration | default: 300 }}; - let demoPause = {{ site.conference.live.demo.pause | default: 10 }}; - let demoStart = confStart - confDur/demoDur*demoPause; - let demoEnd = confEnd + confDur/demoDur*demoPause; - let liveTimer; let streamVideoTimer; let streamInfoTimer; - const loadData = function () { - // Fetch schedule from external file - $.getJSON('{{ site.baseurl }}/assets/js/data.json', function(json) { - data = json; + const loadData = () => { + // Load schedule + const request = new Request(window.conference.config.baseurl + '/assets/js/data.json'); + + fetch(request) + .then(response => + response.json() + ) + .then(d => { + data = d; + }) + .catch((error) => { + console.log(error); }); }; - const getData = function () { + const getData = () => { // Return data return data; }; - const mod = function (n, m) { + const mod = (n, m) => { // Absolute modulo return ((n % m) + m) % m; }; - const timeNow = function () { + const timeNow = () => { // Current timestamp in seconds return Math.floor(Date.now() / 1000); }; - const timeCont = function () { + const timeCont = () => { // Continuous time (respecting previous pauses) return timeNow() - timeOffset; }; - const timeCycle = function () { + const timeCycle = () => { // Cyclic timestamp in seconds - let actTime = timeNow(); - let relTime = mod(actTime, demoDur + 2*demoPause) / (demoDur + 2*demoPause); - let cycleTime = mod((demoEnd - demoStart) * relTime - timeOffset, (demoEnd - demoStart)) + demoStart; + const actTime = timeNow(); + const relTime = mod(actTime, demoDur + 2*demoPause) / (demoDur + 2*demoPause); + const cycleTime = mod((demoEnd - demoStart) * relTime - timeOffset, (demoEnd - demoStart)) + demoStart; return cycleTime; }; - const time = function () { + const time = () => { // Return app time if (freezeTime) { return timeFrozen; @@ -81,7 +84,7 @@ window.conference.live = (function() { } }; - const pauseTime = function () { + const pauseTime = () => { // Pause app time if (!freezeTime) { timeFrozen = time(); @@ -91,7 +94,7 @@ window.conference.live = (function() { } }; - const continueTime = function () { + const continueTime = () => { // Continue app time if (freezeTime) { freezeTime = false; @@ -100,7 +103,7 @@ window.conference.live = (function() { } }; - const resetTime = function () { + const resetTime = () => { // Reset app time timeOffset = 0; freezeTime = false; @@ -108,12 +111,12 @@ window.conference.live = (function() { startUpdate(); }; - const setTime = function (newTime, newDay) { + const setTime = (newTime, newDay) => { // Set and pause app time pauseTime(); let dayIdx; - if (arguments.length < 2) { + if (!newDay) { dayIdx = 0; } else if (Number.isInteger(newDay)) { @@ -125,7 +128,7 @@ window.conference.live = (function() { else { dayIdx = data.days.find(o => o.name === newDay); } - let newDate = data.days[dayIdx].date; + const newDate = data.days[dayIdx].date; let d = new Date(newDate); newTime = newTime.split(':'); @@ -136,19 +139,19 @@ window.conference.live = (function() { update(); }; - const getTime = function () { + const getTime = () => { // Return app time as string - let tConvert = time(); + const tConvert = time(); - let d = new Date(tConvert * 1000); - let dStr = d.toISOString().slice(0,10); - let h = d.getHours(); - let m = d.getMinutes(); + const d = new Date(tConvert * 1000); + const dStr = d.toISOString().slice(0,10); + const h = d.getHours(); + const m = d.getMinutes(); return dStr +" "+ h +":"+ (m < 10 ? "0" : "") + m; }; - const timeUnit = function () { + const timeUnit = () => { // App time refresh rate if (demo) { return 0.1; @@ -158,10 +161,10 @@ window.conference.live = (function() { } }; - const delayStart = function (startTime) { + const delayStart = (startTime) => { // Seconds until given startTime occurs - let tNow = time(); - let tUnit = timeUnit(); + const tNow = time(); + const tUnit = timeUnit(); if (demo) { // Convert virtual duration to real duration @@ -178,7 +181,7 @@ window.conference.live = (function() { } }; - let model = { + const model = { set demo(value) { demo = value; resetTime(); @@ -188,18 +191,18 @@ window.conference.live = (function() { } }; - const updateLive = function () { + const updateLive = () => { // Update status all live elements in DOM - let tNow = time(); - let liveShow = document.getElementsByClassName('live-show'); - let liveHide = document.getElementsByClassName('live-hide'); - let liveTime = document.getElementsByClassName('live-time'); - let livePast = document.getElementsByClassName('live-past'); + const tNow = time(); + const liveShow = document.getElementsByClassName('live-show'); + const liveHide = document.getElementsByClassName('live-hide'); + const liveTime = document.getElementsByClassName('live-time'); + const livePast = document.getElementsByClassName('live-past'); // Show elements for a given period for (let i = 0; i < liveShow.length; i++) { - let tStarts = liveShow[i].dataset.start.split(','); - let tEnds = liveShow[i].dataset.end.split(','); + const tStarts = liveShow[i].dataset.start.split(','); + const tEnds = liveShow[i].dataset.end.split(','); for (let k = 0; k < tStarts.length; k++) { if (tNow >= tStarts[k] && tNow < tEnds[k]) { @@ -216,8 +219,8 @@ window.conference.live = (function() { // Hide elements for a given period for (let i = 0; i < liveHide.length; i++) { - let tStarts = liveHide[i].dataset.start.split(','); - let tEnds = liveHide[i].dataset.end.split(','); + const tStarts = liveHide[i].dataset.start.split(','); + const tEnds = liveHide[i].dataset.end.split(','); for (let k = 0; k < tStarts.length; k++) { if (tNow >= tStarts[k] && tNow < tEnds[k]) { @@ -236,7 +239,7 @@ window.conference.live = (function() { // Update duration string for given elements for (let i = 0; i < liveTime.length; i++) { - let t = liveTime[i].dataset.time; + const t = liveTime[i].dataset.time; if (typeof t == "undefined") { break; } @@ -244,17 +247,17 @@ window.conference.live = (function() { let tStr; if (tRel >= -60 && tRel < 0) { - tStr = '{{ site.data.lang[site.conference.lang].live.time.soon | default: "soon" }}'; + tStr = lang.time.soon; } else if (tRel >= 0 && tRel < 60) { - tStr = '{{ site.data.lang[site.conference.lang].live.time.now | default: "now" }}'; + tStr = lang.time.now; } else { if (tRel < 0) { - tStr = '{{ site.data.lang[site.conference.lang].live.time.in | default: "in" }} '; + tStr = lang.time.in; } else { - tStr = '{{ site.data.lang[site.conference.lang].live.time.since | default: "since" }} '; + tStr = lang.time.since; } tRel = Math.abs(tRel); @@ -266,28 +269,28 @@ window.conference.live = (function() { break; } else if (dWeeks > 1) { - tStr += dWeeks +' {{ site.data.lang[site.conference.lang].live.time.weeks | default: "weeks" }}'; + tStr += dWeeks +' '+ lang.time.weeks; } else if (dWeeks == 1) { - tStr += '1 {{ site.data.lang[site.conference.lang].live.time.week | default: "week" }}'; + tStr += '1 '+ lang.time.week; } else if (dDays > 1) { - tStr += dDays +' {{ site.data.lang[site.conference.lang].live.time.days | default: "days" }}'; + tStr += dDays +' '+ lang.time.days; } else if (dDays == 1) { - tStr += '1 {{ site.data.lang[site.conference.lang].live.time.day | default: "day" }}'; + tStr += '1 '+ lang.time.day; } else if (dHours > 1) { - tStr += dHours +' {{ site.data.lang[site.conference.lang].live.time.hours | default: "hours" }}'; + tStr += dHours +' '+ lang.time.hours; } else if (dHours == 1) { - tStr += '1 {{ site.data.lang[site.conference.lang].live.time.hour | default: "hour" }}'; + tStr += '1 '+ lang.time.hour; } else if (dMins > 1) { - tStr += dMins +' {{ site.data.lang[site.conference.lang].live.time.minutes | default: "minutes" }}'; + tStr += dMins +' '+ lang.time.minutes; } else { - tStr += '1 {{ site.data.lang[site.conference.lang].live.time.minute | default: "minute" }}'; + tStr += '1 '+ lang.time.minute; } } @@ -296,7 +299,7 @@ window.conference.live = (function() { // Disable elements for a given period for (let i = 0; i < livePast.length; i++) { - let t = livePast[i].dataset.time; + const t = livePast[i].dataset.time; if (typeof t == "undefined") { break; } @@ -320,7 +323,7 @@ window.conference.live = (function() { } }; - const startUpdateLive = function () { + const startUpdateLive = () => { // Start update timer to update live elements in DOM stopUpdateLive(); updateLive(); @@ -330,377 +333,377 @@ window.conference.live = (function() { liveTimer = setInterval(updateLive, timeUnit() * 1000); } else { - setTimeout(function() { + setTimeout(() => { liveTimer = setInterval(updateLive, timeUnit() * 1000); updateLive(); }, delayStart(confStart) * 1000); } }; - const stopUpdateLive = function () { + const stopUpdateLive = () => { // stopUpdate update timer to update live elements in DOM if (typeof liveTimer !== "undefined") { clearInterval(liveTimer); } }; - {% if site.conference.live.streaming.enable -%} - const streamPause = {{ site.conference.live.streaming.time_pause | default: 60 }}; // in minutes - const streamPrepend = {{ site.conference.live.streaming.time_prepend | default: 5 }}; // in minutes - const streamExtend = {{ site.conference.live.streaming.time_extend | default: 5 }}; // in minutes + let streamModal; - let streamModal; + const getRoom = (roomName) => { + // Return room object for given room name + if (roomName in data.rooms) { + return data.rooms[roomName]; + } + else { + return data.rooms[Object.keys(data.rooms)[0]]; + } + }; - const getRoom = function (roomName) { - // Return room object for given room name - if (roomName in data.rooms) { - return data.rooms[roomName]; - } - else { - return data.rooms[Object.keys(data.rooms)[0]]; - } - }; + const getTalks = (roomName) => { + if (roomName in data.talks) { + return data.talks[roomName]; + } + else { + return false; + } + }; - const getTalks = function (roomName) { - if (roomName in data.talks) { - return data.talks[roomName]; - } - else { - return false; - } - }; - - const getNextTalk = function (roomName) { - // Get talk object for next talk in given room - let timeNow = time(); - let talksHere = getTalks(roomName); - - if (talksHere) { - if (timeNow < talksHere[talksHere.length-1].end) { - for (var i = 0; i < talksHere.length; i++) { - if (timeNow < talksHere[i].end) { - return talksHere[i]; - } + const getNextTalk = (roomName) => { + // Get talk object for next talk in given room + const timeNow = time(); + const talksHere = getTalks(roomName); + + if (talksHere) { + if (timeNow < talksHere[talksHere.length-1].end) { + for (let i = 0; i < talksHere.length; i++) { + if (timeNow < talksHere[i].end) { + return talksHere[i]; } } } - return false; - }; - - const getNextPause = function (roomName) { - // Get time object for next pause in given room - let timeNow = time(); - let talksHere = getTalks(roomName); - - if (talksHere) { - if (timeNow < talksHere[talksHere.length-1].end) { - for (var i = 1; i < talksHere.length; i++) { - if (timeNow < talksHere[i].start && streamPause*60 <= talksHere[i].start - talksHere[i-1].end) { - return { - 'start': talksHere[i-1].end, - 'end': talksHere[i].start, - }; - } + } + return false; + }; + + const getNextPause = (roomName) => { + // Get time object for next pause in given room + const timeNow = time(); + const talksHere = getTalks(roomName); + + if (talksHere) { + if (timeNow < talksHere[talksHere.length-1].end) { + for (let i = 1; i < talksHere.length; i++) { + if (timeNow < talksHere[i].start && streamPause*60 <= talksHere[i].start - talksHere[i-1].end) { + return { + 'start': talksHere[i-1].end, + 'end': talksHere[i].start, + }; } } } - return false; - }; - - const setStreamIframeContent = function (content) { - // Set stream modal iframe to show given text - streamModal.find('iframe').attr('src', ''); - streamModal.find('iframe').addClass('d-none'); - streamModal.find('#stream-placeholder > div').text(content); - streamModal.find('#stream-placeholder').addClass('d-flex'); - }; - - const setStreamIframeSrc = function (href) { - // Set stream modal iframe to show given URL - streamModal.find('iframe').attr('src', href); - streamModal.find('#stream-placeholder').addClass('d-none').removeClass('d-flex'); - streamModal.find('iframe').removeClass('d-none'); - }; - - const setStreamVideo = function (roomName) { - // Update stream modal iframe: - // Show stream with start/pause/end message (for given room) and keep updated - let timeNow = time(); - - let talksHere = getTalks(roomName); - let roomStart, roomEnd; - if (talksHere) { - roomStart = talksHere[0].start; - roomEnd = talksHere[talksHere.length-1].end; - } - else { - // If no program for given room, take overall first and last talk - roomStart = 0; - roomEnd = 0; - for (let roomNameTalk in data.talks) { - talksHere = getTalks(roomNameTalk); - let crntRoomStart = talksHere[0].start; - let crntRoomEnd = talksHere[talksHere.length-1].end; - - if (roomStart == 0 || roomStart > crntRoomStart) { - roomStart = crntRoomStart; - } - if (roomEnd == 0 || roomEnd < crntRoomEnd) { - roomEnd = crntRoomEnd; - } + } + return false; + }; + + const setStreamIframeContent = (content) => { + // Set stream modal iframe to show given text + streamModal.find('iframe').attr('src', ''); + streamModal.find('iframe').addClass('d-none'); + streamModal.find('#stream-placeholder > div').text(content); + streamModal.find('#stream-placeholder').addClass('d-flex'); + }; + + const setStreamIframeSrc = (href) => { + // Set stream modal iframe to show given URL + streamModal.find('iframe').attr('src', href); + streamModal.find('#stream-placeholder').addClass('d-none').removeClass('d-flex'); + streamModal.find('iframe').removeClass('d-none'); + }; + + const setStreamVideo = (roomName) => { + // Update stream modal iframe: + // Show stream with start/pause/end message (for given room) and keep updated + const timeNow = time(); + + const talksHere = getTalks(roomName); + let roomStart, roomEnd; + if (talksHere) { + roomStart = talksHere[0].start; + roomEnd = talksHere[talksHere.length-1].end; + } + else { + // If no program for given room, take overall first and last talk + roomStart = 0; + roomEnd = 0; + for (let roomNameTalk in data.talks) { + talksHere = getTalks(roomNameTalk); + const crntRoomStart = talksHere[0].start; + const crntRoomEnd = talksHere[talksHere.length-1].end; + + if (roomStart == 0 || roomStart > crntRoomStart) { + roomStart = crntRoomStart; + } + if (roomEnd == 0 || roomEnd < crntRoomEnd) { + roomEnd = crntRoomEnd; } } + } - if (typeof streamVideoTimer !== "undefined") { - clearInterval(streamVideoTimer); + if (typeof streamVideoTimer !== "undefined") { + clearInterval(streamVideoTimer); + } + + // Conference not yet started + if (timeNow < roomStart - streamPrepend*60) { + setStreamIframeContent(lang.pre_stream); + + if (!freezeTime) { + streamVideoTimer = setTimeout(setStreamVideo, delayStart(roomStart - streamPrepend*60) * 1000, roomName); } + } - // Conference not yet started - if (timeNow < roomStart - streamPrepend*60) { - setStreamIframeContent('{{ site.data.lang[site.conference.lang].live.pre_stream | default: "Live stream has not started yet." }}'); + // Conference is over + else if (timeNow > roomEnd + streamExtend*60) { + setStreamIframeContent(lang.post_stream); - if (!freezeTime) { - streamVideoTimer = setTimeout(setStreamVideo, delayStart(roomStart - streamPrepend*60) * 1000, roomName); - } + if (!freezeTime && demo) { + streamVideoTimer = setTimeout(setStreamVideo, delayStart(roomEnd - streamPrepend*60) * 1000, roomName); } + } + + // Conference ongoing + else { + const pauseNext = getNextPause(roomName); - // Conference is over - else if (timeNow > roomEnd + streamExtend*60) { - setStreamIframeContent('{{ site.data.lang[site.conference.lang].live.post_stream | default: "Live stream has ended." }}'); + // Currently stream is paused + if (pauseNext && timeNow >= pauseNext.start + streamExtend*60 && timeNow <= pauseNext.end - streamPrepend*60) { + setStreamIframeContent(lang.pause_stream); - if (!freezeTime && demo) { - streamVideoTimer = setTimeout(setStreamVideo, delayStart(roomEnd - streamPrepend*60) * 1000, roomName); + if (!freezeTime) { + streamVideoTimer = setTimeout(setStreamVideo, delayStart(pauseNext.end - streamPrepend*60) * 1000, roomName); } } - - // Conference ongoing + // Currently a talk is active else { - let pauseNext = getNextPause(roomName); + const room = getRoom(roomName); + setStreamIframeSrc(room.href); - // Currently stream is paused - if (pauseNext && timeNow >= pauseNext.start + streamExtend*60 && timeNow <= pauseNext.end - streamPrepend*60) { - setStreamIframeContent('{{ site.data.lang[site.conference.lang].live.pause_stream | default: "Live stream is currently paused." }}'); - - if (!freezeTime) { - streamVideoTimer = setTimeout(setStreamVideo, delayStart(pauseNext.end - streamPrepend*60) * 1000, roomName); + if (!freezeTime) { + if (pauseNext) { + streamVideoTimer = setTimeout(setStreamVideo, delayStart(pauseNext.start + streamExtend*60) * 1000, roomName); } - } - // Currently a talk is active - else { - let room = getRoom(roomName); - setStreamIframeSrc(room.href); - - if (!freezeTime) { - if (pauseNext) { - streamVideoTimer = setTimeout(setStreamVideo, delayStart(pauseNext.start + streamExtend*60) * 1000, roomName); - } - else { - streamVideoTimer = setTimeout(setStreamVideo, delayStart(roomEnd + streamExtend*60) * 1000, roomName); - } + else { + streamVideoTimer = setTimeout(setStreamVideo, delayStart(roomEnd + streamExtend*60) * 1000, roomName); } } } - }; + } + }; - const setStreamInfo = function (roomName) { - // Update stream modal info bar: - // Show next talk and speaker (for given room) and keep updated - let timeNow = time(); - let talkNext = getNextTalk(roomName); + const setStreamInfo = (roomName) => { + // Update stream modal info bar: + // Show next talk and speaker (for given room) and keep updated + const timeNow = time(); + const talkNext = getNextTalk(roomName); - if (typeof streamInfoTimer !== "undefined") { - clearInterval(streamInfoTimer); - } + if (typeof streamInfoTimer !== "undefined") { + clearInterval(streamInfoTimer); + } - if (talkNext && timeNow >= talkNext.start - streamPause*60) { - document.getElementById('stream-info').dataset.time = talkNext.start; - document.getElementById('stream-info-time').dataset.time = talkNext.start; - updateLive(); + if (talkNext && timeNow >= talkNext.start - streamPause*60) { + document.getElementById('stream-info').dataset.time = talkNext.start; + document.getElementById('stream-info-time').dataset.time = talkNext.start; + updateLive(); - streamModal.find('#stream-info-color').removeClass(function (index, className) { - return (className.match(/(^|\s)border-soft-\S+/g) || []).join(' '); - }); - streamModal.find('#stream-info-color').addClass('border-soft-' + talkNext.color); + streamModal.find('#stream-info-color').removeClass((index, className) => { + return (className.match(/(^|\s)border-soft-\S+/g) || []).join(' '); + }); + streamModal.find('#stream-info-color').addClass('border-soft-' + talkNext.color); - streamModal.find('#stream-info-talk').text(talkNext.name).attr('href', talkNext.href); + streamModal.find('#stream-info-talk').text(talkNext.name).attr('href', talkNext.href); - let speakerStr = ''; - for (let i = 0; i < talkNext.speakers.length; i++) { - let speaker = data.speakers[talkNext.speakers[i]]; - if (speaker.href == '') { - speakerStr += speaker.name +', ' - } - else { - speakerStr += ''+ speaker.name +', '; - } - } - speakerStr = speakerStr.slice(0, -2); - streamModal.find('#stream-info-speakers').html(speakerStr); - - if (talkNext.live_links) { - let linksStr = ''; - for (let i = 0; i < talkNext.live_links.length; i++) { - const link = talkNext.live_links[i]; - - linksStr += ''; - if (link.icon) { - linksStr += ' '; - } - linksStr += link.name + ''; - } - streamModal.find('#stream-info-links').html(linksStr).removeClass('d-none'); + let speakerStr = ''; + for (let i = 0; i < talkNext.speakers.length; i++) { + let speaker = data.speakers[talkNext.speakers[i]]; + if (speaker.href == '') { + speakerStr += speaker.name +', ' } else { - streamModal.find('#stream-info-links').addClass('d-none'); + speakerStr += ''+ speaker.name +', '; } + } + speakerStr = speakerStr.slice(0, -2); + streamModal.find('#stream-info-speakers').html(speakerStr); - streamModal.find('#stream-info').removeClass('d-none'); + if (talkNext.live_links) { + let linksStr = ''; + for (let i = 0; i < talkNext.live_links.length; i++) { + const link = talkNext.live_links[i]; - if (!freezeTime) { - streamInfoTimer = setTimeout(setStreamInfo, delayStart(talkNext.end) * 1000, roomName); + linksStr += ''; + if (link.icon) { + linksStr += ' '; + } + linksStr += link.name + ''; } + streamModal.find('#stream-info-links').html(linksStr).removeClass('d-none'); } else { - streamModal.find('#stream-info').addClass('d-none'); + streamModal.find('#stream-info-links').addClass('d-none'); + } - if (!freezeTime) { - if (talkNext) { - streamInfoTimer = setTimeout(setStreamInfo, delayStart(talkNext.start - streamPause*60) * 1000, roomName); - } - else if (demo) { - let talksHere = getTalks(roomName); - if (talksHere) { - streamInfoTimer = setTimeout(setStreamInfo, delayStart(talksHere[0].start - streamPrepend*60) * 1000, roomName); - } + streamModal.find('#stream-info').removeClass('d-none'); + + if (!freezeTime) { + streamInfoTimer = setTimeout(setStreamInfo, delayStart(talkNext.end) * 1000, roomName); + } + } + else { + streamModal.find('#stream-info').addClass('d-none'); + + if (!freezeTime) { + if (talkNext) { + streamInfoTimer = setTimeout(setStreamInfo, delayStart(talkNext.start - streamPause*60) * 1000, roomName); + } + else if (demo) { + let talksHere = getTalks(roomName); + if (talksHere) { + streamInfoTimer = setTimeout(setStreamInfo, delayStart(talksHere[0].start - streamPrepend*60) * 1000, roomName); } } } - }; + } + }; - const setStream = function (roomName) { - // Update stream modal (iframe and info bar) for given room - streamModal.find('.modal-footer .btn').removeClass('active'); - streamModal.find('#stream-select').val(0); + const setStream = (roomName) => { + // Update stream modal (iframe and info bar) for given room + streamModal.find('.modal-footer .btn').removeClass('active'); + streamModal.find('#stream-select').val(0); - // Recover room name in case of empty default - let room = getRoom(roomName); - roomName = room.name; + // Recover room name in case of empty default + const room = getRoom(roomName); + roomName = room.name; - setStreamVideo(roomName); - setStreamInfo(roomName); + setStreamVideo(roomName); + setStreamInfo(roomName); - streamModal.find('#stream-button' + room.id).addClass('active'); - streamModal.find('#stream-select').val(room.id); - }; + streamModal.find('#stream-button' + room.id).addClass('active'); + streamModal.find('#stream-select').val(room.id); + }; - const updateStream = function () { - // Update stream modal for currently active room button - if (streamModal.hasClass('show')) { - let activeButton = streamModal.find('.modal-footer .btn.active'); - let roomName = activeButton.data('room'); + const updateStream = () => { + // Update stream modal for currently active room button + if (streamModal.hasClass('show')) { + let activeButton = streamModal.find('.modal-footer .btn.active'); + let roomName = activeButton.data('room'); - if (typeof roomName !== "undefined") { - setStream(roomName); - } + if (typeof roomName !== "undefined") { + setStream(roomName); } - }; + } + }; - const stopUpdateStream = function () { - // Stop stream modal update timer - if (typeof streamVideoTimer !== "undefined") { - clearInterval(streamVideoTimer); - } - if (typeof streamInfoTimer !== "undefined") { - clearInterval(streamInfoTimer); - } - }; - - const hideModal = function () { - // Close stream modal - streamModal.find('iframe').attr('src', ''); - streamModal.find('.modal-footer .btn').removeClass('active'); - streamModal.find('#stream-select').selectedIndex = -1; - }; - - const setupStream = function () { - // Setup events when modal opens/closes - streamModal = $('#stream-modal'); - - // configure modal opening buttons - streamModal.on('show.bs.modal', function (event) { - let button = $(event.relatedTarget); - let roomName = button.data('room'); - setStream(roomName); - }); - streamModal.on('hide.bs.modal', function () { - hideModal(); - }); + const stopUpdateStream = () => { + // Stop stream modal update timer + if (typeof streamVideoTimer !== "undefined") { + clearInterval(streamVideoTimer); + } + if (typeof streamInfoTimer !== "undefined") { + clearInterval(streamInfoTimer); + } + }; - // configure room selection buttons in modal - streamModal.find('.modal-footer .btn').on('click', function(event) { - event.preventDefault(); + const hideModal = () => { + // Close stream modal + streamModal.find('iframe').attr('src', ''); + streamModal.find('.modal-footer .btn').removeClass('active'); + streamModal.find('#stream-select').selectedIndex = -1; + }; - let roomName = $(this).data('room'); - setStream(roomName); - }); + const setupStream = () => { + // Setup events when modal opens/closes + streamModal = $('#stream-modal'); - // configure room selection menu in modal - streamModal.find('#stream-select').on('change', function(event) { - event.preventDefault(); + // configure modal opening buttons + streamModal.on('show.bs.modal', (event) => { + let button = $(event.relatedTarget); + let roomName = button.data('room'); + setStream(roomName); + }); + streamModal.on('hide.bs.modal', () => { + hideModal(); + }); - let roomName = $(this).children('option:selected').text(); - setStream(roomName); - }); - }; + // configure room selection buttons in modal + streamModal.find('.modal-footer .btn').on('click', function (event) { + event.preventDefault(); - const setup = function () { - loadData(); - startUpdateLive(); - setupStream(); - }; + let roomName = $(this).data('room'); + setStream(roomName); + }); - const update = function () { - updateLive(); - updateStream(); - }; + // configure room selection menu in modal + streamModal.find('#stream-select').on('change', function (event) { + event.preventDefault(); - const startUpdate = function () { - startUpdateLive(); - updateStream(); - }; + let roomName = $(this).children('option:selected').text(); + setStream(roomName); + }); + }; - const stopUpdate = function () { - stopUpdateLive(); - stopUpdateStream(); - }; + const init = (c, l) => { + config = c; + lang = l; - {%- else -%} + confStart = config.time.start; + confEnd = config.time.end; + confDur = confEnd - confStart; - const setup = function () { - loadData(); - startUpdateLive(); - }; + demo = config.demo.enable; + demoDur = config.demo.duration; + demoPause = config.demo.pause; + demoStart = confStart - confDur/demoDur*demoPause; + demoEnd = confEnd + confDur/demoDur*demoPause; - const update = function () { - updateLive(); - }; + stream = config.streaming.enable; + streamPause = config.streaming.pause; + streamPrepend = config.streaming.prepend; + streamExtend = config.streaming.extend; + + loadData(); + startUpdateLive(); + if (stream) { + setupStream(); + } + }; - const startUpdate = function () { - startUpdateLive(); - }; + const update = () => { + updateLive(); + if (stream) { + updateStream(); + } + }; - const stopUpdate = function () { - stopUpdateLive(); - }; + const startUpdate = () => { + startUpdateLive(); + if (stream) { + updateStream(); + } + }; - {%- endif %} + const stopUpdate = () => { + stopUpdateLive(); + if (stream) { + stopUpdateStream(); + } + }; return { - init: setup, + init: init, getData: getData, pauseTime: pauseTime, @@ -713,5 +716,3 @@ window.conference.live = (function() { }; })(); - -window.conference.live.init(); diff --git a/_includes/js/map.js b/_includes/js/map.js index 1298bf9d..92bb08f1 100644 --- a/_includes/js/map.js +++ b/_includes/js/map.js @@ -1,45 +1,38 @@ -window.conference.mapConfig = (function() { +window.conference.mapConfig = (() => { + let config; + let lang; let map; - let mapProvider = "{{ site.conference.map.map_provider | default: 'OpenStreetMap.Mapnik' }}"; - let homeCoord = [{{ site.conference.map.home_coord }}]; - let zoomLevel = {{ site.conference.map.default_zoom | default: 17 }}; + const setup = (elId) => { + map = L.map(elId).setView(config.map.home_coord, config.map.default_zoom); - let setup = function (elId) { - map = L.map(elId).setView(homeCoord, zoomLevel); + L.tileLayer.provider(config.map.map_provider).addTo(map); - L.tileLayer.provider(mapProvider).addTo(map); - - L.easyButton('far fa-star', function(){ - map.flyTo(homeCoord, zoomLevel); - }, '{{ site.data.lang[site.conference.lang].location.focus_conf | default: "Center map on conference location" }}').addTo(map); + L.easyButton('far fa-star', () => { + map.flyTo(config.map.home_coord, config.map.default_zoom); + }, lang.location.focus_conf).addTo(map); L.control.locate({ flyTo: true, strings: { - title: '{{ site.data.lang[site.conference.lang].location.focus_me | default: "Show me where I am" }}' + title: lang.location.focus_me } }).addTo(map); }; - let init = function () { - let elId = 'map'; + const init = (c, l) => { + config = c; + lang = l; + + const elId = 'map'; if (document.getElementById(elId)) { setup(elId); - window.conference.map = map; } }; return { - init: init, - default: { - mapProvider: mapProvider, - homeCoord: homeCoord, - zoomLevel: zoomLevel - } + init: init }; })(); - -window.conference.mapConfig.init(); diff --git a/_includes/js/modal.js b/_includes/js/modal.js index 4134a7d9..f09b542e 100644 --- a/_includes/js/modal.js +++ b/_includes/js/modal.js @@ -1,15 +1,15 @@ -window.conference.modal = (function () { +window.conference.modal = (() => { - let show = function (el, event) { - let button = $(event.relatedTarget); + const show = (el, event) => { + const button = $(event.relatedTarget); - let href = button.data('href'); - let format = button.data('format'); - let title = button.data('title'); - let subtitle = button.data('subtitle'); - let footer = button.data('footer'); + const href = button.data('href'); + const format = button.data('format'); + const title = button.data('title'); + const subtitle = button.data('subtitle'); + const footer = button.data('footer'); - let modal = $(el); + const modal = $(el); modal.find('iframe').attr('src', href); if (title) { @@ -51,8 +51,8 @@ window.conference.modal = (function () { } }; - let hide = function (el) { - let modal = $(el); + const hide = (el) => { + const modal = $(el); modal.find('.modal-title h3').text(''); modal.find('.modal-title h5').text('').addClass('d-none'); @@ -60,8 +60,8 @@ window.conference.modal = (function () { modal.find('.modal-footer p').html(''); }; - let init = function() { - let elSel = '#link-modal'; + const init = () => { + const elSel = '#link-modal'; $(elSel).on('show.bs.modal', function (event) { show(this, event); @@ -76,5 +76,3 @@ window.conference.modal = (function () { }; })(); - -window.conference.modal.init(); diff --git a/_includes/js/program.js b/_includes/js/program.js index a65aa14d..50d6829f 100644 --- a/_includes/js/program.js +++ b/_includes/js/program.js @@ -1,27 +1,25 @@ -window.conference.program = (function() { - let updateHash = function (hash) { - let scrollPosition = $('body').scrollTop() || $('html').scrollTop(); +window.conference.program = (() => { + const updateHash = (hash) => { + const scrollPosition = document.documentElement.scrollTop; window.location.hash = hash; - $('html,body').scrollTop(scrollPosition); + document.documentElement.scrollTop = scrollPosition; }; - let init = function () { + const init = () => { if ($('#day-list')) { // Switch to day if page load with hash - var hash = window.location.hash; + const hash = window.location.hash; if (hash) { $('#day-list a[href="' + hash + '"]').tab('show'); } + // Switch to day if today else { - let d = new Date(); - let dStr = d.getFullYear() +"-"+ (d.getMonth()+1) +"-"+ d.getDate() - // since a timezone compensation is added when passed as string, today's date has also - // to be passed as string (as it is done below) - let today = new Date(dStr); + let today = new Date(); + today.setHours(0,0,0,0); $('a[data-toggle="tab"]').each(function () { - let d = new Date($(this).data('date')); + const d = new Date($(this).data('date')); if (today.getTime() === d.getTime()) { $(this).tab('show'); @@ -41,5 +39,3 @@ window.conference.program = (function() { init: init }; })(); - -window.conference.program.init(); diff --git a/_layouts/config.html b/_layouts/config.html new file mode 100644 index 00000000..337b3e24 --- /dev/null +++ b/_layouts/config.html @@ -0,0 +1,78 @@ +{ + {%- include partials/get_enable_map.html -%} + {%- if enable_map %} + "map": { + "map_provider": "{{ site.conference.map.map_provider | default: 'OpenStreetMap.Mapnik' }}", + "home_coord": [{{ site.conference.map.home_coord }}], + "default_zoom": {{ site.conference.map.default_zoom | default: 17 }} + }, + {%- endif %} + + {% if site.conference.live -%} + "live": { + "time": { + {% assign d = site.data.program.days | first -%} + {%- include partials/get_day_time.html -%} + {%- assign t = day_start_talk -%} + + {%- include partials/get_talk_timestamp.html -%} + {%- assign conf_start = timestamp_start -%} + + {%- assign d = site.data.program.days | last -%} + {%- include partials/get_day_time.html -%} + {%- assign t = day_end_talk -%} + + {%- include partials/get_talk_timestamp.html -%} + {%- assign conf_end = timestamp_end -%} + + "start": {{ conf_start }}, + "end": {{ conf_end }} + }, + + "streaming": { + "enable": {{ site.conference.live.streaming.enable | default: "false" }}, + "pause": {{ site.conference.live.streaming.time_pause | default: 60 }}, + "prepend": {{ site.conference.live.streaming.time_prepend | default: 5 }}, + "extend": {{ site.conference.live.streaming.time_extend | default: 5 }} + }, + + "demo": { + "enable": {{ site.conference.live.demo.enable | default: "false" }}, + "duration": {{ site.conference.live.demo.duration | default: 300 }}, + "pause": {{ site.conference.live.demo.pause | default: 10 }} + } + }, + {%- endif %} + + "lang": { + {%- if enable_map %} + "map": { + "focus_conf": "{{ site.data.lang[site.conference.lang].location.focus_conf | default: "Center map on conference location" }}", + "focus_me": "{{ site.data.lang[site.conference.lang].location.focus_me | default: "Show me where I am" }}" + } + {%- endif -%} + + {%- if site.conference.live and site.conference.live.streaming.enable -%} + {%- if enable_map %},{% endif %} + "live": { + "pre_stream": "{{ site.data.lang[site.conference.lang].live.pre_stream | default: "Live stream has not started yet." }}", + "post_stream": "{{ site.data.lang[site.conference.lang].live.post_stream | default: "Live stream has ended." }}", + "pause_stream": "{{ site.data.lang[site.conference.lang].live.pause_stream | default: "Live stream is currently paused." }}", + "time": { + "soon": "{{ site.data.lang[site.conference.lang].live.time.soon | default: "soon" }}", + "now": "{{ site.data.lang[site.conference.lang].live.time.now | default: "now" }}", + "in": "{{ site.data.lang[site.conference.lang].live.time.in | default: "in" }} ", + "since": "{{ site.data.lang[site.conference.lang].live.time.since | default: "since" }} ", + "weeks": "{{ site.data.lang[site.conference.lang].live.time.weeks | default: "weeks" }}", + "week": "{{ site.data.lang[site.conference.lang].live.time.week | default: "week" }}", + "days": "{{ site.data.lang[site.conference.lang].live.time.days | default: "days" }}", + "day": "{{ site.data.lang[site.conference.lang].live.time.day | default: "day" }}", + "hours": "{{ site.data.lang[site.conference.lang].live.time.hours | default: "hours" }}", + "hour": "{{ site.data.lang[site.conference.lang].live.time.hour | default: "hour" }}", + "minutes": "{{ site.data.lang[site.conference.lang].live.time.minutes | default: "minutes" }}", + "minute": "{{ site.data.lang[site.conference.lang].live.time.minute | default: "minute" }}" + } + } + {%- endif %} + } +} diff --git a/_layouts/data.html b/_layouts/data.html index 9a1374c4..858e91ce 100644 --- a/_layouts/data.html +++ b/_layouts/data.html @@ -1,5 +1,5 @@ -{% if site.conference.live and site.conference.live.streaming.enable -%} { + {% if site.conference.live and site.conference.live.streaming.enable -%} "days": [ {%- for d in site.data.program.days %} { @@ -116,5 +116,6 @@ {%- endunless -%} {%- endfor %} } + + {%- endif %} } -{%- endif -%} diff --git a/assets/js/config.json b/assets/js/config.json new file mode 100644 index 00000000..6562a1e1 --- /dev/null +++ b/assets/js/config.json @@ -0,0 +1,3 @@ +--- +layout: config +--- diff --git a/jekyll-theme-conference.gemspec b/jekyll-theme-conference.gemspec index 71d59d54..0a38d56a 100644 --- a/jekyll-theme-conference.gemspec +++ b/jekyll-theme-conference.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |spec| spec.name = "jekyll-theme-conference" - spec.version = "3.4.1" + spec.version = "3.5.0" spec.authors = ["Lorenz Schmid"] spec.email = ["lorenzschmid@users.noreply.github.com"]