(function() { // Initialization var calendar = { orderBy : 'startTime', showLocation: false, offsetMax : 72, offsetMin : 4, showDeleted : false, singleEvents: true, maxResults : 250 }; // Read config form theme config file Object.assign(calendar, {{ theme.calendar | json }}); var now = new Date(); var timeMax = new Date(); var timeMin = new Date(); timeMax.setHours(now.getHours() + calendar.offsetMax); timeMin.setHours(now.getHours() - calendar.offsetMin); // Build URL const params = { key : calendar.api_key, orderBy : calendar.orderBy, timeMax : timeMax.toISOString(), timeMin : timeMin.toISOString(), showDeleted : calendar.showDeleted, singleEvents: calendar.singleEvents, maxResults : calendar.maxResults }; var request_url = 'https://www.googleapis.com/calendar/v3/calendars/' + calendar.calendar_id + '/events?' + Object.entries(params).map(([key, value]) => `${key}=${encodeURIComponent(value)}`).join('&'); fetchData(); var fetchDataTimer = setInterval(fetchData, 60000); window.addEventListener('pjax:send', () => { clearInterval(fetchDataTimer); }); function fetchData() { var eventList = document.querySelector('.event-list'); if (!eventList) return; fetch(request_url).then(response => { return response.json(); }).then(data => { if (data.items.length === 0) { eventList.innerHTML = '
'; return; } // Clean the event list eventList.innerHTML = ''; var prevEnd = 0; // used to decide where to insert an
data.items.forEach(event => { // Parse data var utc = new Date().getTimezoneOffset() * 60000; var start = event.start.dateTime = new Date(event.start.dateTime || (new Date(event.start.date).getTime() + utc)); var end = event.end.dateTime = new Date(event.end.dateTime || (new Date(event.end.date).getTime() + utc)); tense = judgeTense(now, start, end); // 0:now 1:future -1:past if (tense === 1 && prevEnd < now) { eventList.innerHTML += '
'; } eventDOM = buildEventDOM(tense, event); eventList.innerHTML += eventDOM; prevEnd = end; }); }); } function getRelativeTime(current, previous) { var msPerMinute = 60 * 1000; var msPerHour = msPerMinute * 60; var msPerDay = msPerHour * 24; var msPerMonth = msPerDay * 30; var msPerYear = msPerDay * 365; var elapsed = current - previous; var tense = elapsed > 0 ? 'ago' : 'later'; elapsed = Math.abs(elapsed); if ( elapsed < msPerHour ) { return Math.round(elapsed / msPerMinute) + ' minutes ' + tense; } else if ( elapsed < msPerDay ) { return Math.round(elapsed / msPerHour) + ' hours ' + tense; } else if ( elapsed < msPerMonth ) { return 'about ' + Math.round(elapsed / msPerDay) + ' days ' + tense; } else if ( elapsed < msPerYear ) { return 'about ' + Math.round(elapsed / msPerMonth) + ' months ' + tense; } else { return 'about' + Math.round(elapsed / msPerYear) + ' years' + tense; } } function judgeTense(now, eventStart, eventEnd) { if (eventEnd < now) { return -1; } else if (eventStart > now) { return 1; } else { return 0; } } function buildEventDOM(tense, event) { var tenseClass = ''; var start = event.start.dateTime; var end = event.end.dateTime; switch(tense) { case 0 : // now tenseClass = 'event-now'; break; case 1 : // future tenseClass = 'event-future'; break; case -1: // past tenseClass = 'event-past'; break; default: throw 'Time data error'; } var durationFormat = { weekday: 'short', hour : '2-digit', minute : '2-digit' }; var relativeTimeStr = (tense === 0) ? 'NOW' : getRelativeTime(now, start); var durationStr = start.toLocaleTimeString([], durationFormat) + ' - ' + end.toLocaleTimeString([], durationFormat); var locationDOM = ''; if (calendar.showLocation && event.location) { locationDOM = '' + event.location + ''; } var eventContent = `

${event.summary} ${relativeTimeStr}

${locationDOM} ${durationStr}
`; return eventContent; } })();