/* global CONFIG */ // https://developers.google.com/calendar/api/v3/reference/events/list (function() { // Initialization const calendar = { orderBy : 'startTime', showLocation: false, offsetMax : 72, offsetMin : 4, showDeleted : false, singleEvents: true, maxResults : 250 }; // Read config form theme config file Object.assign(calendar, CONFIG.calendar); const now = new Date(); const timeMax = new Date(); const 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 }; const request_url = new URL(`https://www.googleapis.com/calendar/v3/calendars/${calendar.calendar_id}/events`); Object.entries(params).forEach(param => request_url.searchParams.append(...param)); function getRelativeTime(current, previous) { const msPerMinute = 60 * 1000; const msPerHour = msPerMinute * 60; const msPerDay = msPerHour * 24; const msPerMonth = msPerDay * 30; const msPerYear = msPerDay * 365; let elapsed = current - previous; const 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; } return 'about ' + Math.round(elapsed / msPerYear) + ' years' + tense; } function buildEventDOM(tense, event, start, end) { const durationFormat = { weekday: 'short', hour : '2-digit', minute : '2-digit' }; const relativeTime = tense === 'now' ? 'NOW' : getRelativeTime(now, start); const duration = start.toLocaleTimeString([], durationFormat) + ' - ' + end.toLocaleTimeString([], durationFormat); let location = ''; if (calendar.showLocation && event.location) { location = `<span class="event-location event-details">${event.location}</span>`; } let description = ''; if (event.description) { description = `<span class="event-description event-details">${event.description}</span>`; } const eventContent = `<section class="event event-${tense}"> <h2 class="event-summary"> ${event.summary} <span class="event-relative-time">${relativeTime}</span> </h2> ${location} <span class="event-duration event-details">${duration}</span> ${description} </section>`; return eventContent; } function fetchData() { const eventList = document.querySelector('.event-list'); if (!eventList) return; fetch(request_url.href).then(response => { return response.json(); }).then(data => { if (data.items.length === 0) { eventList.innerHTML = '<hr>'; return; } // Clean the event list eventList.innerHTML = ''; let prevEnd = 0; // used to decide where to insert an <hr> const utc = new Date().getTimezoneOffset() * 60000; data.items.forEach(event => { // Parse data const start = new Date(event.start.dateTime || (new Date(event.start.date).getTime() + utc)); const end = new Date(event.end.dateTime || (new Date(event.end.date).getTime() + utc)); let tense = 'now'; if (end < now) { tense = 'past'; } else if (start > now) { tense = 'future'; } if (tense === 'future' && prevEnd < now) { eventList.insertAdjacentHTML('beforeend', '<hr>'); } eventList.insertAdjacentHTML('beforeend', buildEventDOM(tense, event, start, end)); prevEnd = end; }); }); } fetchData(); const fetchDataTimer = setInterval(fetchData, 60000); document.addEventListener('pjax:send', () => { clearInterval(fetchDataTimer); }); })();